java nio---wakeup实现原理

  我们都知道select()方法是阻塞的,只有在注册的channel有事件发生时
才会返回,但是如果程序需要立即返回怎么办呢,这你就涉及到一个wakeup()方法。该方法的作用就是让select()方法返回。
  首先来看一下WindowsSelectorImpl对象的初始化过程
//在加载WindowsSelectorImpl类时创建一个管道
private final Pipe wakeupPipe = Pipe.open();

WindowsSelectorImpl(SelectorProvider var1) throws IOException {
        super(var1);
        //获取管道read端的文件描述符
        this.wakeupSourceFd = ((SelChImpl)this.wakeupPipe.source()).getFDVal();
        SinkChannelImpl var2 = (SinkChannelImpl)this.wakeupPipe.sink();
        //获取管道write端的文件描述符
        var2.sc.socket().setTcpNoDelay(true);
        this.wakeupSinkFd = var2.getFDVal();
        //将read端的文件描述符保存到pollWrapper数组的第一位
        this.pollWrapper.addWakeupSocket(this.wakeupSourceFd, 0);
    }
void addWakeupSocket(int var1, int var2) {
		//添加句柄
        this.putDescriptor(var2, var1);
        //添加事件掩码(可读)
        this.putEventOps(var2, 1);
    }

接下来看看wakeup是如何让程序返回的

public Selector wakeup() {
        Object var1 = this.interruptLock;
        synchronized(this.interruptLock) {
        //如果中断触发标志interruptTriggered为false
            if (!this.interruptTriggered) {
            //此方法的作用是向管道随机写入内容
                this.setWakeupSocket();
                this.interruptTriggered = true;
            }

            return this;
        }
    }

  在初始化WindowsSelectorImpl对象的时候也向selector注册了管道的read端,并将事件掩码设为可读。因此当向管道的write端写入数据后,管道的read端会变为可读,selector轮询发现有事件被触发,就会返回。

wakeup方法的用处

  当辅助线线程完成从poll方法返回后会触发threadFinished()方法,该方法的作用有三个

  1. 向管道中写入数据,让别的辅助线程也能够迅速返回。
  2. 更新待完成线程数
  3. 唤醒等待中的主线程
private synchronized void threadFinished() {
            if (this.threadsToFinish == WindowsSelectorImpl.this.threads.size()) {
            //如果此线程是第一个完成poll调用的,则通过管道让其余线程也返回(包括主线程)
                WindowsSelectorImpl.this.wakeup();
            }
            --this.threadsToFinish;
            if (this.threadsToFinish == 0) {
            //如果所有的辅助线程都已经返回则唤醒处于等待状态的主线程
                this.notify();
            }

        }

  同样当主线程完成poll调用后也会触发wakeup方法的调用,具体如下:

  1. 当主线程率先完成poll调用后唤醒其他辅助线程
  2. 如果辅助线程没有全部返回则等待
private synchronized void waitForHelperThreads() {
		//如果此线程是第一个完成poll调用的,则通过管道让其余线程也返回(包括主线程)
            if (this.threadsToFinish == WindowsSelectorImpl.this.threads.size()) {
                WindowsSelectorImpl.this.wakeup();
            }

            while(this.threadsToFinish != 0) {
                try {
                	//如果辅助线程没有全部返回,则等待
                    WindowsSelectorImpl.this.finishLock.wait();
                } catch (InterruptedException var2) {
                    Thread.currentThread().interrupt();
                }
            }

        }

总结

  主线程和辅助线程通过wakeup方法相互唤醒,具体规则如下:

  1. 当主线程率先完成poll调用时,进入waitForHelperThreads()方法,在该方法中唤醒所有辅助线程,并等待所有辅助线程完成后唤醒主线程
  2. 当一个辅助线程率先完成poll调用时,通过wakeup()方法唤醒其他线程。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值