论坛首页 Java企业应用论坛

关于Socket的一个异常

浏览 2892 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2010-04-07   最后修改:2010-04-07
    近日在无聊,写了一些关于socket通讯的demo,结果出现了一个Connection rest 异常信息,然后看了一下源码
此异常的出现,是在java.net.SocketInputStream中抛出来的,首先来看一下源码:
 
class SocketInputStream extends FileInputStream
	{
   		 static {
       	 init();
   	 	}
    
   	 private boolean eof;
   	 private PlainSocketImpl impl = null;
    	 private byte temp[]; 
    	 private Socket socket = null;
	

	/*********

			部分省略
				************/
	if (impl.isConnectionReset()) {     /*异常由此处抛出*/
	    throw new SocketException("Connection reset");
	}



由此可见,是因为调用方法的时候触发了 PlainSocketImpl中的 isConnectionReset()方法,继续寻根问底,看看到底isConnectionReset()做了
什么操作,继续看代码:
class PlainSocketImpl extends SocketImpl
{
    /*

	**
		**  部分代码省略 *****/
    
    private int resetState;
    private int CONNECTION_RESET = 2;
    private Object resetLock = new Object();


	public boolean isConnectionReset() {
	synchronized (resetLock) {
	    return (resetState == CONNECTION_RESET);
	}
    }
	/*

		**
			**  部分代码省略 *****/
}




仔细看,在isConnectionReset方法中 对创建的对象流进行了加锁?然后注释都没有写这个地方用来干嘛的?????
而且大家仔细看下,这个类名不是public的,在类的注释中有这样一句话:         
This implementation does not implement any security checks.
对这些很是不解,其中有一句这样的代码:
private Object resetLock = new Object();
这些东西看起来只是对他进行了安全控制,用的同步的方法,为什么这么弄?原本是想把问题好好搞明白,结果越看越深,更迷糊了,后面又继续查看源代码就有
  java.net.SocketImpl
     * @see        java.net.SocketImplFactory#createSocketImpl()
     * @see        java.net.ServerSocket#setSocketFactory(java.net.SocketImplFactory)
     * @see        SecurityManager#checkListen
这些了,看来还得找多点时间好好研究一下才会使问题得到解决,并对此有更深的体会。
   发表时间:2010-04-11  
这个叫虚拟锁。

通常我们对一个类A中的两个方法进行同步操作是在方法上加锁:
public synchronized boolean methodA() {
            /*省略*/
    }

public synchronized boolean methodB() {
            /*省略*/
    }


在这种情况下,多个线程分别同时调用A实例的methodA(),methodB()方法时,只有一个线程可以获得同步锁,执行一个方法,其他线程需要等待这个线程释放锁了再竞争同步锁,执行他们要执行的方法。

这通常是在methodA和methodB方法中存在对相同共享数据的情况下,为了避免数据的争用而采用的同步操作。如果说这两个方法之间不存在资源争用,但又都需要同步的时候,如PlainSocketImpl类中的releaseFD()和isConnectionReset()这两个方法,你仔细看一下PlainSocketImpl的代码:
class PlainSocketImpl extends SocketImpl {
    /*省略*/
    private Object fdLock = new Object();
    /*省略*/
    private Object resetLock = new Object();
    /*省略*/
    public final void releaseFD() {
        synchronized (fdLock) {
            fdUseCount--;
            if (fdUseCount == -1) {
                if (fd != null) {
                    try {
                        socketClose();
                    } catch (IOException e) {
                    } finally {
                        fd = null;
                    }
                }
            }
        }
    }

    public boolean isConnectionReset() {
        synchronized (resetLock) {
            return (resetState == CONNECTION_RESET);
        }
    }
    /*省略*/
}


如果采用前面这种对方法或者对类的同步,那么假设A线程在执行PlainSocketImpl实例的releaseFD()时,B线程需要执行PlainSocketImpl实例的isConnectionReset()方法,就需要等待A线程释放同步锁,这种等待是无意义的。

为了解决这个问题,PlainSocketImpl类采用了后面这种虚拟锁的手段,创建了两个虚拟锁对象fdLock和resetLock并分别同步,这样在两个线程分别调用这两个方法时,他们获得的是不同对象的锁,互相没有任何竞争,就可以同步运行,只有两个线程同时调用releaseFD()或isConnectionReset()方法时才会争用同一个锁。
0 请登录后投票
   发表时间:2010-04-11  
近来也在做Socket开发。
明天再试试这个东西。
0 请登录后投票
   发表时间:2010-04-16  
FeiXing2008 写道
近来也在做Socket开发。
明天再试试这个东西。

呵呵,谢谢yechw
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics