Socket socket = new Socket(); socket.connect(new InetSocketAddress("10.0.0.1",8080),20000);
在timeout时间到时,就会抛出connect timed out异常
1 2 3 4 5 6 7 8 9
Exception in thread "main" java.net.SocketTimeoutException: connect timed out at java.net.DualStackPlainSocketImpl.waitForConnect(Native Method) at java.net.DualStackPlainSocketImpl.socketConnect(DualStackPlainSocketImpl.java:85) at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350) at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206) at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188) at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:172) at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392) at java.net.Socket.connect(Socket.java:589)
socketTimeout
Enable/disable SO_TIMEOUT with the specified timeout, in milliseconds. With this option set to a non-zero timeout, a read() call on the InputStream associated with this Socket will block for only this amount of time. If the timeout expires, a java.net.SocketTimeoutException is raised, though the Socket is still valid. The option must be enabled prior to entering the blocking operation to have effect. The timeout must be > 0. A timeout of zero is interpreted as an infinite timeout.
服务端,只要让客户端能连接上就行,不发送数据
1 2 3 4 5
ServerSocket serverSocket = new ServerSocket(8080); while ( true) { Socket socket = serverSocket.accept(); new Thread(new P(socket)).start(); }
客户端,进行读数据
1 2 3
Socket socket = new Socket(); socket.connect(new InetSocketAddress("localhost",8080),20000); socket.setSoTimeout(3000);
3s后,就抛出Read timed out
1 2 3 4 5 6
java.net.SocketTimeoutException: Read timed out at java.net.SocketInputStream.socketRead0(Native Method) at java.net.SocketInputStream.socketRead(SocketInputStream.java:116) at java.net.SocketInputStream.read(SocketInputStream.java:170) at java.net.SocketInputStream.read(SocketInputStream.java:141) at java.net.SocketInputStream.read(SocketInputStream.java:223)
nio
对NIO,看网上一些示例基本没有关注到这一点,所以值得思考,难道是nio不需要关注timeout?
客户端对服务器的连接:
1 2 3 4
Selector selector = Selector.open(); InetSocketAddress isa = new InetSocketAddress(host, port); // 调用open静态方法创建连接到指定主机的SocketChannel SocketChannel sc = SocketChannel.open(isa);
public void connect(){ try{ selector = Selector.open(); InetSocketAddress isa = new InetSocketAddress(host, port); //10秒连接超时 new Timer().schedule(tt, 10000); // 调用open静态方法创建连接到指定主机的SocketChannel sc = SocketChannel.open(isa); // 设置该sc以非阻塞方式工作 sc.configureBlocking(false); // 将Socketchannel对象注册到指定Selector sc.register(selector, SelectionKey.OP_READ); Message msg = new Message(); msg.what = 0; msg.obj = sc; handler.sendMessage(msg); // 连接成功 new Thread(new NIOReceiveThread(selector, handler)).start(); }catch (IOException e) { e.printStackTrace(); handler.sendEmptyMessage(-1); // IO异常 } } TimerTask tt = new TimerTask(){ @Override public void run(){ if (sc == null || !sc.isConnected()){ try{ throw new SocketTimeoutException("连接超时"); }catch (SocketTimeoutException e){ e.printStackTrace(); handler.sendEmptyMessage(-6); // 连接超时 } } } };
在stackoverflow上有人回答了Read timeout for an NIO SocketChannel?
You are using a Selector, in which case you have a select timeout which you can play with, and if it goes off (select(timeout) returns zero) you close all the registered channels, or
You are using blocking mode, in which case you might think you should be able to call Socket.setSoTimeout() on the underlying socket (SocketChannel.socket()), and trap the SocketTimeoutException that is thrown when the timeout expires during read(), but you can’t, because it isn’t supported for sockets originating as channels, or
You are using non-blocking mode without a Selector, in which case you need to change to case (1).
NettyResponseFuture responseFuture = NettyClient.this.removeCallback(response.getRequestId()); if (responseFuture == null) { LoggerUtil.warn( "NettyClient has response from server, but resonseFuture not exist, requestId={}", response.getRequestId()); return null; }
// don't need to notifylisteners, because onSuccess or // onFailure or cancel method already call notifylisteners return getValueOrThrowable(); } else { long waitTime = timeout - (System.currentTimeMillis() - createTime);
if (waitTime > 0) { for (;;) { try { lock.wait(waitTime); } catch (InterruptedException e) { }
// 3.如果连接正在创建中,则加入queue if (target instanceof EmptyChannel) { boolean result = jobs.offer(callback); if (result) { return; } else { throw new RuntimeException("Can't connet to target server and the waiting queue is full"); } }
/** * 类加载时间性能测试 * * 看一下类加载需要消耗的时间 * Created by Jack on 2018/10/8. */ public class ClassLoaderTest1 { public static void main(String[] args) throws SQLException { long s = System.nanoTime();
LoaderClass loaderClass = new LoaderClass(); long e = System.nanoTime(); //第一次时间 System.out.println(e - s); e = System.nanoTime(); //第二次实例,但已经加载过,不再需要加载 LoaderClass loaderClass1 = new LoaderClass(); long e1 = System.nanoTime(); //第二次时间 System.out.println(e1 - e); } } //输出 2409737 396
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) { if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) { throw new IllegalStateException( "Cannot initialize context because there is already a root application context present - " + "check whether you have multiple ContextLoader* definitions in your web.xml!"); }
Log logger = LogFactory.getLog(ContextLoader.class); servletContext.log("Initializing Spring root WebApplicationContext"); if (logger.isInfoEnabled()) { logger.info("Root WebApplicationContext: initialization started"); } long startTime = System.currentTimeMillis();
try { // Determine parent for root web application context, if any. ApplicationContext parent = loadParentContext(servletContext);
// Store context in local instance variable, to guarantee that // it is available on ServletContext shutdown. this.context = createWebApplicationContext(servletContext, parent); servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
2.2.2、这里所设置的初始值通常情况下是数据类型默认的零值(如0、0L、null、false等),而不是被在Java代码中被显式地赋予的值。 假设一个类变量的定义为:public static int value = 3; 那么变量value在准备阶段过后的初始值为0,而不是3,因为这时候尚未开始执行任何Java方法,而把value赋值为3的putstatic指令是在程序编译后,存放于类构造器方法之中的,所以把value赋值为3的动作将在初始化阶段才会执行
/** * 测试类加载及初始化顺序问题 * Created by jack01.zhu on 2018/9/28. */ public class ClassInit { private static ClassInit singleton = new ClassInit(); public static int counter1; public static int counter2 = 0; private ClassInit() { counter1++; counter2++; } public static ClassInit getSingleton() { return singleton; } }
/** * 通过输出结果,推测类加载过程 * Created by jack01.zhu on 2018/9/28. */ public class ClassInitTestMain {
// 首先检查,jvm中是否已经加载了对应名称的类,findLoadedClass(String )方法实际上是findLoadedClass0方法的wrapped方法,做了检查类名的工 //作,而findLoadedClass0则是一个native方法,通过底层来查看jvm中的对象。 Class c = findLoadedClass(name); if (c == null) {//类还未加载 try { if (parent != null) { //在类还未加载的情况下,我们首先应该将加载工作交由父classloader来处理。 c = parent.loadClass(name, false); } else { //返回一个由bootstrap class loader加载的类,如果不存在就返回null c = findBootstrapClassOrNull(name); } } catch (ClassNotFoundException e) { // ClassNotFoundException thrown if class not found
// from the non-null parent class loader }
if (c == null) { // If still not found, then invoke findClass in order // to find the class. c = findClass(name);//这里是我们的入手点,也就是指定我们自己的类加载实现 } } if (resolve) { resolveClass(c);//用来做类链接操作 } return c; }
public static void main(String[] args) { testFast(100); testSlow(100); }
private static void testFast(int threadLocalCount) { final FastThreadLocal<String>[] caches = new FastThreadLocal[threadLocalCount]; final Thread mainThread = Thread.currentThread(); for (int i = 0; i < threadLocalCount; i++) { caches[i] = new FastThreadLocal(); } Thread t = new FastThreadLocalThread(new Runnable() { @Override public void run() { for (int i = 0; i < threadLocalCount; i++) { caches[i].set("float.lu"); } long start = System.nanoTime(); for (int i = 0; i < threadLocalCount; i++) { for (int j = 0; j < 1000000; j++) { caches[i].get(); } } long end = System.nanoTime(); System.out.println("take[" + TimeUnit.NANOSECONDS.toMillis(end - start) + "]ms"); LockSupport.unpark(mainThread); }
}); t.start(); LockSupport.park(mainThread); }
private static void testSlow(int threadLocalCount) { final ThreadLocal<String>[] caches = new ThreadLocal[threadLocalCount]; final Thread mainThread = Thread.currentThread(); for (int i=0;i<threadLocalCount;i++) { caches[i] = new ThreadLocal(); } Thread t = new Thread(new Runnable() { @Override public void run() { for (int i=0;i<threadLocalCount;i++) { caches[i].set("float.lu"); } long start = System.nanoTime(); for (int i=0;i<threadLocalCount;i++) { for (int j=0;j<1000000;j++) { caches[i].get(); } } long end = System.nanoTime(); System.out.println("take[" + TimeUnit.NANOSECONDS.toMillis(end - start) + "]ms"); LockSupport.unpark(mainThread); }
public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) { @SuppressWarnings("unchecked") T result = (T)e.value; return result; } } return setInitialValue(); }
private Entry getEntry(ThreadLocal<?> key) { int i = key.threadLocalHashCode & (table.length - 1); Entry e = table[i]; if (e != null && e.get() == key) return e; else return getEntryAfterMiss(key, i, e); } private Entry getEntryAfterMiss(ThreadLocal<?> key, int i, Entry e) { Entry[] tab = table; int len = tab.length;
while (e != null) { ThreadLocal<?> k = e.get(); if (k == key) return e; if (k == null) expungeStaleEntry(i); else i = nextIndex(i, len); e = tab[i]; } return null; }
如果key值相等,直接返回value
如果key不相等,使用循环线性探测,一直找到最后一个元素
FastThreadLocal.get()
1 2 3 4 5 6 7 8 9 10 11 12 13
public final V get(InternalThreadLocalMap threadLocalMap) { Object v = threadLocalMap.indexedVariable(index); if (v != InternalThreadLocalMap.UNSET) { return (V) v; }
return initialize(threadLocalMap); } public Object indexedVariable(int index) { Object[] lookup = indexedVariables; return index < lookup.length? lookup[index] : UNSET; }
public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); } private void set(ThreadLocal<?> key, Object value) {
// We don't use a fast path as with get() because it is at // least as common to use set() to create new entries as // it is to replace existing ones, in which case, a fast // path would fail more often than not.
Entry[] tab = table; int len = tab.length; int i = key.threadLocalHashCode & (len-1);
for (Entry e = tab[i]; e != null; e = tab[i = nextIndex(i, len)]) { ThreadLocal<?> k = e.get();
public FastThreadLocal() { index = InternalThreadLocalMap.nextVariableIndex(); }
UnpaddedInternalThreadLocalMap
1 2 3 4 5 6 7 8 9 10 11
Object[] indexedVariables;
public static int nextVariableIndex() { int index = nextIndex.getAndIncrement(); if (index < 0) { nextIndex.decrementAndGet(); throw new IllegalStateException("too many thread-local indexed variables"); } return index; }