源码阅读:理解反应器模式在javaNIO中的实现-Channel2

接上文:
源码阅读:理解反应器模式在javaNIO中的实现-Channel

上文的最后是这么说的:

接下来要先看看socketChannel具体connect的实现方式,以及两者对应的open方法,是如何通过SelectorProvider开启channel的(这就要先看看selector了)。

本文先看前半部分:connect的实现方式

那么就开始吧:

 public boolean connect(SocketAddress var1) throws IOException {
        boolean var2 = false;
        //首先是加上读写锁
        synchronized(this.readLock) {
            synchronized(this.writeLock) {
            //确保开启并未连接(这边通过本地变量state来判断
            //如果state = 2,则已连接;如果state=1,则正在连接中
            //以及如果isOpen为false,均抛出异常
                this.ensureOpenAndUnconnected();
            //判断连接地址是否符合ipv4或者ipv6格式
                InetSocketAddress var5 = Net.checkAddress(var1);
            //获得安全管理器
            //这里简单地介绍一下SecurityManager
            //当运行未知的Java程序的时候,该程序可能有恶意代码(删除系
            //统文件、重启系统等),为了防止运行恶意代码对系统产生影响,需要对运行的代码的权限进行控制,这时候就要启用Java安
            //全管理器。这里用于判断是否允许能够连接主机地址。
                SecurityManager var6 = System.getSecurityManager();
                if (var6 != null) {
                    var6.checkConnect(var5.getAddress().getHostAddress(), var5.getPort());
                }

                boolean var10000;
            //用于在注册时阻塞进程
                synchronized(this.blockingLock()) {
                    int var8 = 0;

                    try {
                        try {
                            this.begin();
                            synchronized(this.stateLock) {
                                if (!this.isOpen()) {
                                    boolean var10 = false;
                                    return var10;
                                }

                                if (this.localAddress == null) {
                                    NetHooks.beforeTcpConnect(this.fd, var5.getAddress(), var5.getPort());
                                }

                                this.readerThread = NativeThread.current();
                            }

                            do {
                                InetAddress var9 = var5.getAddress();
                                if (var9.isAnyLocalAddress()) {
                                    var9 = InetAddress.getLocalHost();
                                }

                                var8 = Net.connect(this.fd, var9, var5.getPort());
                            } while(var8 == -3 && this.isOpen());
                        } finally {
                            this.readerCleanup();
                            this.end(var8 > 0 || var8 == -2);

                            assert IOStatus.check(var8);

                        }
                    } catch (IOException var27) {
                        this.close();
                        throw var27;
                    }

                    synchronized(this.stateLock) {
                        this.remoteAddress = var5;
                        if (var8 <= 0) {
                            if (!this.isBlocking()) {
                                this.state = 1;
                            } else {
                                assert false;
                            }
                        } else {
                            this.state = 2;
                            if (this.isOpen()) {
                                this.localAddress = Net.localAddress(this.fd);
                            }

                            var10000 = true;
                            return var10000;
                        }
                    }
                }

                var10000 = false;
                return var10000;
            }
        }
    }

从begin()方法开始分析

 private Interruptible interruptor;
    private volatile Thread interrupted;
 protected final void begin() {
        if (interruptor == null) {
            interruptor = new Interruptible() {
                    public void interrupt(Thread target) {
                        synchronized (closeLock) {
                            if (!open)
                                return;
                            open = false;
                            interrupted = target;
                            try {
                                AbstractInterruptibleChannel.this.implCloseChannel();
                            } catch (IOException x) { }
                        }
                    }};
        }
        blockedOn(interruptor);
        Thread me = Thread.currentThread();
        if (me.isInterrupted())
            interruptor.interrupt(me);
    }

首先,interruptor是啥东西?

引用https://www.cnblogs.com/jenkov/p/juc_interrupt.html

interrupt(),在一个线程中调用另一个线程的interrupt()方法,即会向那个线程发出信号——线程中断状态已被设置。至于那个线程何去何从,由具体的代码实现决定。
isInterrupted(),用来判断当前线程的中断状态(true or false)。
interrupted()是个Thread的static方法,用来恢复中断状态,名字起得额🙄。

可以看到,在Interruptible的初始化时去获取关闭锁,如果关闭锁是开启的,则设置interrupted为目标线程。通过AbstractInterruptibleChannel.this.implCloseChannel();方法去关闭channel。
在Thread类中找到blockedOn的实现:
是设置interruptible为Thread的blocker。

 /* Set the blocker field; invoked via sun.misc.SharedSecrets from java.nio code
     */
    void blockedOn(Interruptible b) {
        synchronized (blockerLock) {
            blocker = b;
        }
    }

接着是获得当前线程,并interrput中断该线程。

  if (me.isInterrupted())
            interruptor.interrupt(me);

注意这里:当线程已中断,再中断该线程(这是啥意思,理解不了,哪位大神解释一下)
目前理解:begin()方法的作用就是中断线程。
先看下去:

synchronized(this.stateLock) {
                                if (!this.isOpen()) {
                                    boolean var10 = false;
                                    return var10;
                                }

                                if (this.localAddress == null) {
                                    NetHooks.beforeTcpConnect(this.fd, var5.getAddress(), var5.getPort());
                                }

                                this.readerThread = NativeThread.current();
                            }

这里去同步获得stateLock这个常量,实现锁(stateLock就是锁,只有获得这个资源,才可以执行方法体里面的方法)
接下来,如果当前channel没有开启,直接返回false。
NetHooks.beforeTcpConnect(this.fd, var5.getAddress(), var5.getPort());这个方法点进去很深,大致就是获得tcp连接。
然后就是获得本地的读线程。

  do {
                                InetAddress var9 = var5.getAddress();
                                if (var9.isAnyLocalAddress()) {
                                    var9 = InetAddress.getLocalHost();
                                }

                                var8 = Net.connect(this.fd, var9, var5.getPort());
                            } while(var8 == -3 && this.isOpen());
                        } finally {
                            this.readerCleanup();
                            this.end(var8 > 0 || var8 == -2);

                            assert IOStatus.check(var8);

                        }

最后是一个do-while-finally方法
大致就是获得与本地地址进行连接,最终关闭读线程,并通过end()方法结束channel的io操作
(在var8>0 || var8 ==-2为true的条件下,这个参数值的含义貌似没地方能看到。)

总结:
connect方法不断地将本地地址与远程ip端口进行连接,直到连接成功,并中断当前线程。

接下来看看finishConnect方法:

public boolean finishConnect() throws IOException {
        //同样地先给读写加上锁
        synchronized(this.readLock) {
            synchronized(this.writeLock) {
                boolean var10000;
                synchronized(this.stateLock) {
                    if (!this.isOpen()) {
                        throw new ClosedChannelException();
                    }
                    //如果state==2,即代表已经连接成功,return true
                    if (this.state == 2) {
                        var10000 = true;
                        return var10000;
                    }
                    //如果!=1,直接抛出异常,因为该方法是在连接pendi//ng(即正在连接中)的时候被调用
                    if (this.state != 1) {
                        throw new NoConnectionPendingException();
                    }
                }

                int var3 = 0;

                try {
                    label525: {
                        boolean var29 = false;

                        boolean var6;
                        label506: {
                            try {
                                var29 = true;
                                this.begin();
                                synchronized(this.blockingLock()) {
                                    label480: {
                                        label494: {
                                            synchronized(this.stateLock) {
                                                if (!this.isOpen()) {
                                                    var6 = false;
                                                    break label494;
                                                }

                                                this.readerThread = NativeThread.current();
                                            }

                                            if (!this.isBlocking()) {
                                                do {
                                                    var3 = checkConnect(this.fd, false, this.readyToConnect);
                                                } while(var3 == -3 && this.isOpen());
                                            } else {
                                                do {
                                                    while(true) {
                                                        var3 = checkConnect(this.fd, true, this.readyToConnect);
                                                        if (var3 == 0) {
                                                            continue;
                                                        }
                                                        break;
                                                    }
                                                } while(var3 == -3 && this.isOpen());
                                            }

                                            var29 = false;
                                            break label480;
                                        }

                                        var29 = false;
                                        break label506;
                                    }
                                }
                            } finally {
                                if (var29) {
                                    synchronized(this.stateLock) {
                                        this.readerThread = 0L;
                                        if (this.state == 3) {
                                            this.kill();
                                            var3 = 0;
                                        }
                                    }

                                    this.end(var3 > 0 || var3 == -2);

                                    assert IOStatus.check(var3);

                                }
                            }

                            synchronized(this.stateLock) {
                                this.readerThread = 0L;
                                if (this.state == 3) {
                                    this.kill();
                                    var3 = 0;
                                }
                            }

                            this.end(var3 > 0 || var3 == -2);

                            assert IOStatus.check(var3);
                            break label525;
                        }

                        synchronized(this.stateLock) {
                            this.readerThread = 0L;
                            if (this.state == 3) {
                                this.kill();
                                var3 = 0;
                            }
                        }

                        this.end(var3 > 0 || var3 == -2);

                        assert IOStatus.check(var3);

                        return var6;
                    }
                } catch (IOException var38) {
                    this.close();
                    throw var38;
                }

                if (var3 > 0) {
                    synchronized(this.stateLock) {
                        this.state = 2;
                        if (this.isOpen()) {
                            this.localAddress = Net.localAddress(this.fd);
                        }
                    }

                    var10000 = true;
                    return var10000;
                } else {
                    var10000 = false;
                    return var10000;
                }
            }
        }
    }

开始的方法类似,这边有这么一个用法

  label494: {
            synchronized(this.stateLock) {
                if (!this.isOpen()) {
                    var6 = false;
                    break label494;
                }

这个label494一个是定义了一个方法,如果被break了,就不在执行下去了。

public class test {
    public static void main(String[] args) {
        int i = 0;
        fuck454:
        {
            i = i + 1;
            if (i == 1) {
                break fuck454;
            }
            System.out.println(i);
        }
    }
}

结果不会输出,因为已经break了。
继续看:


    if (!this.isBlocking()) {
        do {
            var3 = checkConnect(this.fd, false, this.readyToConnect);
        } while(var3 == -3 && this.isOpen());
    } else {
        do {
            while(true) {
                var3 = checkConnect(this.fd, true, this.readyToConnect);
                if (var3 == 0) {
                    continue;
                }
                break;
            }
        } while(var3 == -3 && this.isOpen());
    }

直到var3!=3或者该channel被关闭了,否则一直检查是否连接上。
最终无论是否成功都关闭线程并关闭channel。
总结:
finishChannel在connect方法被调用之后就可能会被调用,其会一直轮询判断是否已经连接成功,若成功,关闭开启的线程,结束channel的IO操作。
那么为什么要用finishChannel呢?

如果SocketChannel在非阻塞模式下,此时调用connect(),该方法可能在连接建立之前就返回了。为了确定连接是否建立,可以调用finishConnect()的方法(如果成功连接会返回true)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值