Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

这个并发取号逻辑是否 可以这样 进一步优化? #190

Open
ZJRui opened this issue Mar 27, 2022 · 1 comment
Open

这个并发取号逻辑是否 可以这样 进一步优化? #190

ZJRui opened this issue Mar 27, 2022 · 1 comment

Comments

@ZJRui
Copy link

ZJRui commented Mar 27, 2022

在getIdFromSegmentBuffer 方法中, 假设 当前Segment已经没有可用id了,当前线程A 启动线程B 准备NextSegment。 假设此时已经有100个线程阻塞在取号的方,具体也就是waitAndSleep 方法的地方。 当线程B准备就绪NextSegment后, 线程C及时发现SegmentBuffer准备就绪并先获取到了cpu,这个时候线程C会执行Segment的切换工作。切换之后将SegmentBuffer的nextReady设置为false。 对于线程A和其他被阻塞的线程而言,当这些线程 从waitAndSleep方法返回 后 需要 依次获取写锁,然后从当前Segment中取号。显然这些线程没必要依次获取写锁,而且获取SegmentBuffer写锁 会影响 另外的其他尚未被阻塞线程并发使用读锁从当前Segment中获取id。这是第一种情况。

第二种情况就是,假设线程B 准备nextSegment失败了,此时已经有了100个线程处于阻塞状态waitAndSleep,那么这100个线程会依次获取写锁并检查发现SegmentBuffer的nextReady为false,然后返回
取号失败的结果 这些线程就退出了,因此触发nextSegment的准备工作需要 等待下一次取号请求。

按照我的理解:对于唤醒后的线程,如果SegmentBuffer的nextReady为false 则当前线程 没必要通过获取读锁来取号。 只需要走正常的取号流程就可以了。这个时候对于第二种情况也会有改善,因为走了正常的取号流程 也就相当于会启动新的线程执行nextSegment的初始化工作,而不是直接返回取号失败结果。

 public Result getIdFromSegmentBuffer(final SegmentBuffer buffer) {
        while (true) {
            buffer.rLock().lock();
            try {
                final Segment segment = buffer.getCurrent();
                if (!buffer.isNextReady() && (segment.getIdle() < 0.9 * segment.getStep()) && buffer.getThreadRunning().compareAndSet(false, true)) {
                    service.execute(new Runnable() {
                        @Override
                        public void run() {
                            Segment next = buffer.getSegments()[buffer.nextPos()];
                            boolean updateOk = false;
                            try {
                                updateSegmentFromDb(buffer.getKey(), next);
                                updateOk = true;
                                logger.info("update segment {} from db {}", buffer.getKey(), next);
                            } catch (Exception e) {
                                logger.warn(buffer.getKey() + " updateSegmentFromDb exception", e);
                            } finally {
                                if (updateOk) {
                                    buffer.wLock().lock();
                                    buffer.setNextReady(true);
                                    buffer.getThreadRunning().set(false);
                                    buffer.wLock().unlock();
                                } else {
                                    buffer.getThreadRunning().set(false);
                                }
                            }
                        }
                    });
                }
                long value = segment.getValue().getAndIncrement();
                if (value < segment.getMax()) {
                    return new Result(value, Status.SUCCESS);
                }
            } finally {
                buffer.rLock().unlock();
            }
            waitAndSleep(buffer);

              //这个地方优化
            buffer.wLock().lock();
            try {
                final Segment segment = buffer.getCurrent();
                long value = segment.getValue().getAndIncrement();
                if (value < segment.getMax()) {
                    return new Result(value, Status.SUCCESS);
                }
                if (buffer.isNextReady()) {
                    buffer.switchPos();
                    buffer.setNextReady(false);
                } else {
                     //这个地方优化
                    logger.error("Both two segments in {} are not ready!", buffer);
                    return new Result(EXCEPTION_ID_TWO_SEGMENTS_ARE_NULL, Status.EXCEPTION);
                }
            } finally {
                buffer.wLock().unlock();
            }
        }
    }

@thelight1 @Yaccc
##191

@Ccccccai777
Copy link

(只需要走正常的取号流程就可以了。这个时候对于第二种情况也会有改善)您指的是在调用一次getIdFromSegmentBuffer方法吗

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants