ForkJoinPool
æ˜?Java SE 7 新功能“分å?¾l“åˆæ¡†æž¶â€çš„æ ¸å¿ƒ¾c»ï¼ŒçŽ°åœ¨å¯èƒ½ä¹ähé—®æÓ|åQŒä½†æˆ‘觉得它˜qŸæ—©ä¼šæˆä¸ÞZ¸»‹¹ã€‚分å?¾l“åˆæ¡†æž¶æ˜¯ä¸€ä¸ªæ¯”较特ŒDŠçš„¾U¿ç¨‹æ± 框æžÓž¼Œä¸“用于需è¦å°†ä¸€ä¸ªä“QåŠ¡ä¸æ–分解æˆåä“Q务(分å‰åQ‰ï¼Œå†ä¸æ–进行汇æ€Õd¾—到最¾lˆç»“果(¾l“åˆåQ‰çš„计算˜q‡ç¨‹ã€‚æ¯”èµ·ä¼ ¾lŸçš„¾U¿ç¨‹æ± ç±» ThreadPoolExecutor
åQ?code>ForkJoinPool 实现了工作窃å–算法,使得½Iºé—²¾U¿ç¨‹èƒ½å¤Ÿä¸ÕdŠ¨åˆ†æ‹…ä»Žåˆ«çš„çº¿½E‹åˆ†è§£å‡ºæ¥çš„åä“Q务,从而让所有的¾U¿ç¨‹éƒ½å°½å¯èƒ½å¤„于饱满的工作状æ€ï¼Œæé«˜æ‰§è¡Œæ•ˆçއã€?/p>
ForkJoinPool
æä¾›äº†ä¸‰¾cÀL–¹æ³•æ¥è°ƒåº¦åä“Q务:
execute
¾pÕdˆ—invoke
å’?invokeAll
submit
¾pÕdˆ—Future
对象�/dd>
åä“Q务由 ForkJoinTask
的实例æ¥ä»£è¡¨ã€‚它是一个抽象类åQŒJDK 为我们æä¾›äº†ä¸¤ä¸ªå®žçްåQ?code>RecursiveTask å’?RecursiveAction
åQŒåˆ†åˆ«ç”¨äºŽéœ€è¦å’Œä¸éœ€è¦è¿”回计½Ž—结果的åä“Q务ã€?code>ForkJoinTask æä¾›äº†ä¸‰ä¸ªé™æ€çš„ invokeAll
æ–ÒŽ³•æ¥è°ƒåº¦åä»ÕdŠ¡åQŒæ³¨æ„åªèƒ½åœ¨ ForkJoinPool
执行计算的过½E‹ä¸è°ƒç”¨å®ƒä»¬ã€?/p>
ForkJoinPool
å’?ForkJoinTask
˜q˜æä¾›äº†å¾ˆå¤šè®©ähçœÆDб¾~äØ•çš„å…¬å…±æ–¹æ³•ï¼Œå…¶å®žå®ƒä»¬å¤§å¤šæ•°éƒ½æ˜¯å…¶å†…éƒ¨å®žçŽ°åŽ»è°ƒç”¨çš„åQŒå¯¹äºŽåº”用开å‘äh员æ¥è¯´æ„义ä¸å¤§ã€?/p>
下é¢ä»¥ç»Ÿè®?D 盘文件个æ•îCØ“ä¾‹ã€‚è¿™å®žé™…ä¸Šæ˜¯å¯¹ä¸€ä¸ªæ–‡ä»¶æ ‘çš„é历,我们需è¦é€’归地统计æ¯ä¸ªç›®å½•下的文件数é‡ï¼Œæœ€åŽæ±‡æ€»ï¼Œéžå¸¸é€‚åˆç”¨åˆ†å?¾l“åˆæ¡†æž¶æ¥å¤„ç†ï¼š
// 处ç†å•个目录的ä“QåŠ? public class CountingTask extends RecursiveTask<Integer> { private Path dir; public CountingTask(Path dir) { this.dir = dir; } @Override protected Integer compute() { int count = 0; List<CountingTask> subTasks = new ArrayList<>(); // è¯Õd–目录 dir çš„å路径ã€? try (DirectoryStream<Path> ds = Files.newDirectoryStream(dir)) { for (Path subPath : ds) { if (Files.isDirectory(subPath, LinkOption.NOFOLLOW_LINKS)) { // å¯ÒŽ¯ä¸ªå目录都新å»ÞZ¸€ä¸ªåä»ÕdŠ¡ã€? subTasks.add(new CountingTask(subPath)); } else { // é‡åˆ°æ–‡äšgåQŒåˆ™è®¡æ•°å™¨å¢žåŠ?1ã€? count++; } } if (!subTasks.isEmpty()) { // 在当å‰çš„ ForkJoinPool 上调度所有的åä“Q务ã€? for (CountingTask subTask : invokeAll(subTasks)) { count += subTask.join(); } } } catch (IOException ex) { return 0; } return count; } } // 用一ä¸?ForkJoinPool 实例调度“æ€ÖM“Q务â€ï¼Œç„¶åŽæ•¬è¯·æœŸå¾…¾l“果…â€? Integer count = new ForkJoinPool().invoke(new CountingTask(Paths.get("D:/")));
在我的笔记本上,¾l多‹Æ¡è¿è¡Œè¿™ŒDµä»£ç ,耗费的时间稳定在 600 豪秒左å³ã€‚普通线½E‹æ± åQ?code>Executors.newCachedThreadPool()åQ‰è€—æ—¶ 1100 毫秒左å³åQŒèƒöè§å·¥ä½œçªƒå–的优势ã€?/p>
¾l“æŸæœ¬æ–‡å‰ï¼Œæˆ‘们æ¥å›´è§‚一个最¼œžå¥‡çš„结果:å•线½E‹ç®—法(使用 Files.walkFileTree(...)
åQ‰æ¯”˜q™ä¸¤ä¸ªéƒ½å¿«ï¼Œòq›_‡è€—æ—¶ 550 毫秒åQè¿™è¦å‘Šæˆ‘们òq‰™žå¼•入多线½E‹å°±èƒ½ä¼˜åŒ–性能åQŒåƈ™å»è¦å…ˆç»˜q‡å¤š‹Æ¡æµ‹è¯•æ‰èƒ½ä¸‹¾l“论ã€?/p>
å‰é¢å·²ç»çœ‹åˆ°åQ?code>Socket ¾cÈš„ getInputStream()
å’?getOutStream()
æ–ÒŽ³•分别获å–套接å—的输入‹¹å’Œè¾“出‹¹ã€‚输入æµç”¨æ¥è¯Õd–˜qœç«¯å‘é€è¿‡æ¥çš„æ•°æ®åQŒè¾“出æµåˆ™ç”¨æ¥å‘˜qœç«¯å‘逿•°æ®ã€?/p>
使用套接å—的输入‹¹è¯»å–æ•°æ®æ—¶åQŒå½“å‰çº¿½E‹ä¼š˜q›å…¥é˜Õd¡žçжæ€ï¼Œç›´åˆ°å¥—æŽ¥å—æ”¶åˆîC¸€äº›æ•°æ®äØ“æ¢ï¼ˆäº¦å³å¥—接å—的接收¾~“冲区有å¯ç”¨æ•°æ®åQ‰ã€‚该输入‹¹çš„ available()
æ–ÒŽ³•åªæ˜¯˜q”回接收¾~“冲区的å¯ç”¨å—节数é‡åQŒä¸å¯èƒ½çŸ¥é“˜qœç«¯˜q˜è¦å‘é€å¤šž®‘å—节。ä‹É用输入æµçš„æ—¶å€™ï¼Œæœ€å¥½å…ˆž®†å®ƒåŒ…装ä¸ÞZ¸€ä¸?BufferedInputStream
åQŒå› 䏸™¯»å–接收缓冲区ž®†å¯¼è‡?JVM 和底层系¾lŸä¹‹é—´çš„切æ¢åQŒåº”当尽é‡å‡ž®‘åˆ‡æ¢æ¬¡æ•îC»¥æé«˜æ€§èƒ½ã€?code>BufferedInputStream çš„ç¼“å†²åŒºå¤§å°æœ€å¥½è®¾ä¸ºå¥—æŽ¥å—æŽ¥æ”¶¾~“冲区的大å°ã€?/p>
如果直接调用输入‹¹çš„ close()
æ–ÒŽ³•æ¥å…³é—它åQŒåˆ™ž®†å¯¼è‡´å¥—接å—被关é—。对æ¤ï¼ŒSocket
¾cÀL供了一ä¸?shutdownInput()
æ–ÒŽ³•æ¥ç¦ç”¨è¾“å…¥æµã€‚调用该æ–ÒŽ³•åŽï¼Œæ¯æ¬¡è¯ÀL“作都ž®†è¿”å›?EOF
åQŒæ— 法å†è¯Õd–˜qœç«¯å‘é€çš„æ•°æ®ã€‚对˜q™ä¸ª EOF
的检‹¹‹ï¼Œä¸åŒçš„输入æµåŒ…装体现å‡ÞZ¸åŒçš„¾l“æžœåQŒå¯èƒ½è¯»åˆ?-1 个å—节,å¯èƒ½è¯Õdˆ°çš„å—½W¦ä¸²ä¸?null
åQŒè¿˜å¯èƒ½æ”¶åˆ°ä¸€ä¸?EOFException
½{‰ç‰ã€‚ç¦ç”¨è¾“å…¥æµåŽï¼Œ˜qœç«¯è¾“出‹¹çš„è¡ŒäØ“æ˜¯åã^å°ç›¸å…³çš„åQ?/p>
¼›ç”¨è¾“å…¥‹¹è¿™¿UæŠ€æœ¯åÆˆä¸å¸¸ç”¨ã€?/p>
套接å—的输出æ“作实际上仅仅将数æ®å†™åˆ°å‘é€ç¼“冲区内,当å‘é€ç¼“冲区填满且上‹Æ¡çš„å‘逿ˆåŠŸåŽåQŒç”±åº•层¾pÈ»Ÿè´Ÿè´£å‘é€ã€‚如果å‘é€ç¼“冲区的剩余空间ä¸å¤Ÿï¼Œå½“剾U¿ç¨‹ž®×ƒ¼šé˜Õd¡žã€‚和输入‹¹ç±»ä¼û|¼Œæœ€å¥½å°†è¾“出‹¹åŒ…è£…äØ“ BufferedOutputStream
�/p>
如果套接å—çš„åŒå‘都ä‹Éç”?ObjectInputStream
å’?ObjectOutputStream
æ¥è¯»å†?Java 对象åQŒåˆ™å¿…须先创å»?ObjectOutputStream
åQŒå› ä¸?ObjectInputStream
åœ¨æž„é€ çš„æ—¶å€™ä¼šè¯•å›¾è¯Õd–对象头部åQŒå¦‚æžœåŒå‘都先创å»?ObjectInputStream
åQŒåˆ™ä¼šäº’相ç‰å¾…对方的输出åQŒé€ æˆæ»é”åQ?/p>
// 创å¾çš„顺åºä¸èƒ½é¢ å€’ï¼ ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream()); ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
¾cÖM¼¼äºŽè¾“å…¥æµåQŒå…³é—输出æµä¹Ÿå¯¼è‡´å…³é—套接å—åQŒæ‰€ä»?Socket
¾cÕdŒæ äh供了一ä¸?shutdownOutput()
æ¥ç¦ç”¨è¾“出æµã€‚ç¦ç”¨è¾“出æµåŽï¼Œå·²å†™å…¥å‘é€ç¼“冲区的数æ®ä¼šæ£å¸¸å‘é€ï¼Œä¹‹åŽçš„ä“Q何写æ“ä½œéƒ½ä¼šå¯ÆD‡´ IOException
åQŒä¸”˜qœç«¯çš„输入æµå§‹ç»ˆä¼šè¯»åˆ?EOF
。ç¦ç”¨è¾“出æµéžå¸¸æœ‰ç”¨åQŒä¾‹å¦‚套接å—çš„åŒå‘都在å‘é€å®Œæ¯•æ•°æ®å޼›ç”¨è¾“å…¥‹¹ï¼Œç„¶åŽåŒæ–¹éƒ½ä¼šæ”¶åˆ° EOF
åQŒä»Žè€ŒçŸ¥é“æ•°æ®å·²¾l全部交æ¢å®Œæ¯•,å¯ä»¥å®‰å…¨å…³é—套接å—。直接关é—套接å—ä¼šåŒæ—¶å…³é—输入æµå’Œè¾“出æµåQŒä¸”æ–å¼€˜qžæŽ¥åQŒè¾¾ä¸åˆ°˜q™ç§æ•ˆæžœã€?/p>
如果è¦ä‹É用浘q›è¡Œè¾“入和输出,ž®±åªèƒ½ç”¨é˜Õd¡žæ¨¡å¼çš„套接å—。这里æ€È»“一下阻塞套接å—的优¾~ºç‚¹ã€‚先看看优点åQ?/p>
但在性能斚w¢æœ‰è‡´å‘½çš„¾~ºç‚¹åQ?/p>
下一½‹‡æ–‡ç« 开始探讨ä‹É用基äº?NIO 的套接å—通é“和缓冲区实现伸羃性更强的 TCP 套接å—ã€?/p>
ServerSocket
¾cÕd’Œ Socket
¾c»éƒ½æä¾›äº†å¤šä¸ªå…¬å…±æž„é€ æ–¹æ³•ã€‚ä¸åŒçš„æž„é€ æ–¹æ³•ä¸ä»…å¸¦çš„å‚æ•îC¸åŒï¼Œæ‰€å…ähœ‰çš„æ„ä¹‰ä¹Ÿä¸ä¸€æ —÷€‚下é¢åˆ†åˆ«è§£æžè¿™ä¸¤ä¸ª¾cÈš„实例åˆå§‹åŒ–过½E‹ã€?/p>
ServerSocket
实例的åˆå§‹åŒ–ServerSocket
¾cÀLä¾›äº†å››ä¸ªæž„é€ å™¨åQ?/p>
public ServerSocket(int port) throws IOException
public ServerSocket(int port, int backlog) throws IOException
public ServerSocket(int port, int backlog, InetAddress bindAddr) throws IOException
public ServerSocket() throws IOException
另傿ž„é€ å™¨ç”¨æ¥åˆ›å¾å·²ç»‘定的æœåŠ¡å™¨å¥—æŽ¥å—åQŒä¹Ÿž®±æ˜¯è¯´æž„é€ æˆåŠŸåŽå®ƒå°±å·²ç»å¼€å§‹ä¾¦å¬æŒ‡å®šçš„端å£åQŒä¸”能够调用 accept()
æ–ÒŽ³•æ¥æŽ¥å—客æˆïL«¯˜qžæŽ¥ã€‚é»˜è®¤æž„é€ å™¨åˆ™ä¼šåˆ›å¾æœªç»‘定的æœåŠ¡å™¨å¥—æŽ¥å—åQŒæž„é€ æˆåŠŸåŽå¿…须手动ž®†å…¶¾l‘定åˆîC¸€ä¸ªæœ¬åœ°åœ°å€æ‰èƒ½ç”¨ï¼Œåœ¨ç»‘定之å‰å¯ä»¥è¿›è¡Œä¸€äº›é€‰é¡¹é…ç½®ã€?/p>
æ€Èš„æ¥è¯´åQŒå¸¦å‚æž„é€ å™¨æä¾›äº†ä¸‰ä¸ªå‚敎ͼš
port
backlog
accept()
æ–ÒŽ³•åQ‰ï¼Œå®ƒå°±ä¼šè¢«ä»Žé˜Ÿåˆ—丿U»é™¤ã€?code>backlog 傿•°ž®Þq”¨äºŽæŒ‡å®šé˜Ÿåˆ—的最大长度,默认å€égØ“ 50åQŒä½†˜q™ä¸ªå€¼åªæ˜¯ä¸€ä¸ªå¾è®®ï¼Œåº•层¾pÈ»Ÿå¯èƒ½æ ÒŽ®éœ€è¦è‡ªåŠ¨è°ƒæ•´ã€‚å¦‚æžœé˜Ÿåˆ—æ»¡äº†ï¼Œåˆ™å…¶è¡ŒäØ“æ˜¯åã^å°ç›¸å…³çš„åQšå¾®è½¯çš„ WINSOCK 会拒¾l新的连接,其他实现则什么都ä¸åšã€‚ä¸¥æ ¼åœ°è¯ß_¼Œå¾®èÊY没有éµå®ˆè§„范åQŒç ´å了游æˆè§„则…â€?/dd>
bindAddr
null
åQŒæœåŠ¡å™¨å¥—æŽ¥å—会在所有的本地 IP 地å€åQ?code>0.0.0.0 æˆ?::0
åQ‰ä¸Šä¾¦å¬ã€‚如果希望åªä¾¦å¬ä¸€ä¸ªåœ°å€åQŒåˆ™å¯ä‹Éç”¨è¯¥å‚æ•°ã€?/dd>
å¦‚æžœä½¿ç”¨é»˜è®¤æž„é€ å™¨åQŒåœ¨¾l‘定地å€å‰ï¼Œ˜q˜å¯ä»¥åšäº›é…¾|®ã€‚绑定æ“作由两个 bind
æ–ÒŽ³•定义åQŒå‚æ•°ç±»ä¼égºŽå¸¦å‚æž„é€ å™¨ã€‚é…¾|®é¡¹åŒ…括以下斚w¢åQˆéƒ½å¿…须在绑定å‰é…ç½®åQ‰ï¼š
setReuseAddress(boolean on)
æ–ÒŽ³•é…ç½®åQŒå¯¹åº”底层系¾lŸçš„ SO_REUSEADDR
套接å—选项。JDK 没有定义该选项的默认倹{€‚如果该选项ä¸?false
åQŒåˆ™åœ¨å…³é—?TCP ˜qžæŽ¥æ—Óž¼Œä¸ÞZº†ä¿è¯å¯é 性,该连接å¯èƒ½åœ¨å…³é—åŽçš„一ŒD‰|—¶é—ß_¼ˆå¤§çº¦ä¸¤åˆ†é’Ÿï¼‰å†…ä¿æŒè¶…时状æ€ï¼ˆé€šå¸¸¿UîCØ“ TIME_WAIT
çŠ¶æ€æˆ– 2MSL
½{‰å¾…状æ€ï¼‰åQŒè¿™ŒD‰|—¶é—´é‡Œæ— 法ž®†æ–°å»ºçš„æœåŠ¡å™¨å¥—æŽ¥å—¾l‘定到åŒä¸€ä¸ªåœ°å€ã€‚在开å‘阶ŒDµï¼ŒæœåС噍å¯èƒ½ä¸æ–é‡å¯ï¼Œæ‰“开攚w€‰é¡¹ä¼šéžå¸¸æœ‰ç”¨ã€?/dd>
setReceiveBufferSize(int size)
æ–ÒŽ³•é…ç½®åQŒå¯¹åº”底层系¾lŸçš„ SO_RCVBUF
套接å—选项åQŒå•使˜¯å—节。《RFC 1323 - TCP Extensions for High Performance》将¾~“冲区大ž®å®šä¹‰äØ“ 64KBã€‚è¯¥é€‰é¡¹åªæ˜¯ä¸€ä¸ªå¾è®®å€û|¼Œåº•层¾pÈ»Ÿå¯èƒ½æ ÒŽ®éœ€è¦è‡ªè¡Œè°ƒæ•´ã€?/dd>
setSoTimeout(int timeout)
æ–ÒŽ³•é…ç½®åQŒå¯¹åº”底层系¾lŸçš„ SO_TIMEOUT
套接å—选项åQŒå•使˜¯æ¯«ç§’。默认å€égØ“ 0ã€‚è¯¥é€‰é¡¹å½±å“ accept
æ–ÒŽ³•的阻塞时间长度,如果‘…æ—¶ž®†å¼•å?SocketTimeoutException
。如果设ä¸?0åQŒåˆ™è¡¨ç¤ºæ°æ€¸‘…æ—¶ã€?/dd>
setPerformancePreferences(int connectionTime, int latency, int bandwidth)
æ–ÒŽ³•é…置。这三个数值分别表½CºçŸ˜qžæŽ¥æ—‰™—´ã€ä½Žå»¶è¿Ÿå’Œé«˜å¸¦å®½çš„相寚w‡è¦æ€§ï¼Œæ•°å€ÆD¶Šå¤§åˆ™‘Šé‡è¦ï¼›å…¶å„自的¾l对值没有æ„义。该æ–ÒŽ³•çš„åˆè¡äh˜¯ä¸ÞZº†è®?Java èƒ½åœ¨ç”¨éž TCP/IP 实现的套接å—环境下工作得更好åQŒæŸäº›éœ€è¦å¯¹¾|‘络˜q›è¡Œè°ƒä¼˜çš„程åºä¹Ÿå¯ä»¥ž®†è¿™ä¸‰ä¸ªé¦–é€‰é¡¹ä½œäØ“é…ç½®å‚æ•°æä¾›¾l™ç”¨æˆ—÷€?/dd>
Socket
实例的åˆå§‹åŒ–Socket
¾cÀL供了å…ä¸ªå…¬å…±æž„é€ å™¨åQˆå·²˜q‡æ—¶çš„除外)åQ?/p>
public Socket(String host, int port) throws UnknownHostException, IOException
public Socket(InetAddress address, int port) throws IOException
public Socket(String host, int port, InetAddress localAddr, int localPort) throws IOException
public Socket(InetAddress address, int port, InetAddress localAddr, int localPort) throws IOException
public Socket()
public Socket(Proxy proxy)
å‰å››ä¸ªæž„é€ å™¨åˆ›å¾å·²è¿žæŽ¥çš„客户端套接å—åQŒä¹Ÿž®±æ˜¯è¯´æž„é€ çš„æ—¶å€™å°±ä¼šåŽ»˜qžæŽ¥æœåŠ¡å™¨ã€‚å‰ä¸¤ä¸ªæž„é€ å™¨éœ€è¦æä¾›æœåŠ¡å™¨çš„åœ°å€å’Œç«¯å£ä½œä¸ºå‚敎ͼŒæœ¬åœ°åœ°å€å’Œç«¯å£ç”±¾pÈ»Ÿè‡ªåŠ¨åˆ†é…åQ›åŽä¸¤ä¸ªå…许手动指定本地地å€å’Œç«¯å£ï¼Œä½†æžž®‘ä‹É用。åŽä¸¤ä¸ªæž„é€ å™¨åˆ›å¾æœªè¿žæŽ¥çš„套接å—,创å¾åŽéœ€è¦è°ƒç”?connect
æ–ÒŽ³•手动˜qžæŽ¥åQŒè¿žæŽ¥ä¹‹å‰å¯ä»¥åšä¸€äº›é…¾|®ã€‚最åŽä¸€ä¸ªæž„é€ å™¨æŽ¥å—ä¸€ä¸ªä»£è¡¨ä»£ç†æœåС其çš?Proxy
对象åQŒJDK æ”¯æŒ HTTP å’?SOCKSåQˆV4 æˆ?V5åQ‰ä¸¤¿U代ç†ç±»åž‹ã€?/p>
在连接å‰åQŒå®¢æˆïL«¯å¥—接å—ä¸ä»…åƒæœåŠ¡å™¨å¥—æŽ¥å—é‚£æ ·å¯ä»¥è®„¡½®æ˜¯å¦é‡ç”¨æœ¬åœ°åœ°å€ã€ç¼“冲区大å°ã€è¶…时值和性能首选项åQŒè¿˜èƒ½å¤Ÿé…置以下å„项åQˆéƒ½å¿…须在连接å‰é…ç½®åQ‰ï¼š
setKeepAlive(boolean on)
æ–ÒŽ³•é…ç½®åQŒå¯¹åº”底层系¾lŸçš„ SO_KEEPALIVE
套接å—选项。默认å€égØ“ false
。如果打开该选项åQŒåˆ™å¥—接å—会定期自动å‘é€ä¿æŒæ´»è·ƒçš„æŽ¢æµ‹æ€§æ¶ˆæ¯ï¼Œ¾cÖM¼¼äºŽå¿ƒè·Ïx£€‹¹‹ã€‚æ ¹æ®ã€ŠRFC 1122 - Requirements for Internet Hosts》的规定åQŒä¿æŒæ´»è·ƒæœºåˆ¶åªæ˜?TCP 的一个å¯é€‰åŠŸèƒ½ï¼Œå¦‚æžœæ”¯æŒçš„è¯åQŒé»˜è®¤å¿…™åÖMØ“ false
åQŒè€Œä¸”˜q™ç§æœºåˆ¶é»˜è®¤åœ¨æˆåŠŸå¾ç«‹è¿žæŽ¥åŽåQŒä¸”˜qžç®‹ä¸¤å°æ—¶æ²¡æœ‰æ•°æ®ä¼ 输的情况下æ‰ä¼šè¢«‹È€‹z…R€‚从å¦ä¸€æ–šw¢æ¥çœ‹åQŒé€šè¿‡å¥—接å—çš„ I/O æ“作完全å¯ä»¥çŸ¥é“˜qžæŽ¥æ˜¯å¦˜q˜æœ‰æ•ˆï¼Œæ‰€ä»¥è¯¥é€‰é¡¹çš„实用ähå€ég¸å¤§ã€?/dd>
setOOBInline(boolean on)
æ–ÒŽ³•é…ç½®åQŒå¯¹åº”底层系¾lŸçš„ SO_OOBINLINE
套接å—选项。默认å€égØ“ off
。带外数æ®ï¼ˆOut-of-band DataåQ‰ä¹Ÿå«åšç´§æ€¥æ•°æ®ï¼Œè¡¨ç¤ºæ•°æ®å¾ˆé‡è¦ï¼Œéœ€è¦ä‹É用ä¸åŒäºŽå‘逿™®é€šæ•°æ®çš„ä¸€ä¸ªä¸“ç”¨é€šé“æ¥å‘é€ã€‚打开该选项åŽï¼Œž®±å¯ä»¥è°ƒç”?sendUrgentData(int data)
æ–ÒŽ³•å‘é€ä¸€ä¸ªå—节的紧急数æ®ã€‚JDK 对带外数æ®åªæä¾›äº†æœ‰é™æ”¯æŒï¼Œç´§æ€¥æ•°æ®å°†ä¼šå’Œæ™®é€šæ•°æ®ä¸€èµ¯‚¢«æ”¶åˆ°åQŒåÆˆä¸”æ— æ³•è‡ªåŠ¨åŒºåˆ†ã€‚è¯¥é€‰é¡¹å¯¹åº”ç”¨å¼€å‘äh员æ„义ä¸å¤§ã€?/dl>
setSoLinger(boolean on, int linger)
æ–ÒŽ³•é…ç½®åQŒå¯¹åº”底层系¾lŸçš„ SO_LINGER
套接å—é€‰é¡¹ã€‚é»˜è®¤äØ“ false
。该选项åªä¼šå½±å“套接å—的关é—åQŒå…¶ä¸çš„ linger
傿•°è¡¨ç¤º‘…æ—¶æ—‰™—´åQŒå•ä½äØ“¿U’。如果打开攚w€‰é¡¹åQšå¦‚果将 linger
è®¾äØ“ 0åQŒåˆ™å…³é—套接å—的时候,未å‘é€çš„æ•°æ®ä¼šè¢«ä¸¢å¼ƒåQŒä¸”å¦ä¸€ç«¯ä¼šå‡ºçް˜qžæŽ¥è¢«åŒä½ä½“é‡ç½®çš„异常;如果 linger
é?0åQŒåˆ™å…³é—套接å—çš„¾U¿ç¨‹ž®†è¢«é˜Õd¡žåQŒç›´åˆ°æ•°æ®å…¨éƒ¨å‘逿ˆ–‘…æ—¶åQŒè¶…æ—¶åŽçš„行ä¸ÞZ¸Žåº•层¾pÈ»Ÿç›¸å…³åQŒJDK æ— æ³•æŽ§åˆ¶ã€‚å¦‚æžœå…³é—该选项åQŒåˆ™å¥—æŽ¥å—æ£å¸¸å…³é—,数æ®ä¹Ÿä¼šå…¨éƒ¨å‘é€ã€‚ç”±äºŽåº•å±‚å®žçŽ°çš„å·®å¼‚æ€§ï¼Œä¸æå€¡åº”ç”¨å¼€å‘äh员打开该选项ã€?/dd>
setTcpNoDelay(boolean on)
æ–ÒŽ³•é…ç½®åQŒå¯¹åº”底层系¾lŸçš„ TCP_NODELAY
TCP 选项。默认å€égØ“ off
。打开该选项ž®†ç¦ç”?Nagle ½Ž—法åQŒTCP 包会立å³å‘é€ï¼›å…³é—该选项则会å¯ç”¨ Nagle ½Ž—法åQŒå¤šä¸ªè¾ƒž®çš„ TCP åŒ…ä¼šè¢«ç»„åˆæˆä¸€ä¸ªå¤§åŒ…一起å‘é€ï¼Œè™½ç„¶å‘é€åšg˜qŸäº†åQŒä½†æœ‰åˆ©äºŽé¿å…网¾lœæ‹¥å¡žã€‚é»˜è®¤äØ“ false
。该选项对实时性很强的½E‹åºå¯èƒ½æœ‰ç”¨åQŒä½†ä¸€èˆ¬çš„½E‹åºä¸éœ€è¦å…³å¿ƒã€?/dd>
setTrafficClass(int tc)
æ–ÒŽ³•é…ç½®åQŒå¯¹åº”底层系¾lŸçš„“æµé‡ç±»åˆ«â€å¥—接å—属性。该选项用于å‘网¾lœï¼ˆä¾‹å¦‚路由器)æç¤ºä»Žè¯¥å¥—接å—å‘é€çš„包需è¦èŽ·å–哪些æœåŠ¡ç±»åž‹ï¼Œå¯ÒŽœ¬åœ?TCP åè®®æ ˆæ²¡æœ‰åª„å“。IPv4 å’?IPv6 分别定义了多个ä¸åŒçš„å€û|¼Œä¾‹å¦‚ IPv4 ž®?0x08
定义为最大åžåé‡åQ?code>0x10 定义为最ž®åšg˜qŸï¼Œ½{‰ç‰ã€‚å¯ä»¥ç”¨æˆ–è¿½Ž—å°†å¤šä¸ªå€¼åˆòq¶äؓ一个选项。该选项用æ¥è°ƒæ•´æ€§èƒ½åQŒéœ€è¦æ ¹æ®å®žé™…情况设¾|®ã€‚ç”±äºŽåªæ˜¯å¾è®®å€û|¼Œå¯èƒ½è¢«ç½‘¾lœå¿½ç•¥ã€?/dd>
¾|‘上很多关于å•例模å¼å†™æ³•çš„æ–‡ç« ï¼Œä¸å¤–乎饿汉和懒汉两ç§å½¢å¼çš„讨论。很多äh喜欢用懒汉å¼åQŒå› 䏸™§‰å¾—它实现了åšg˜qŸåŠ è½½ï¼Œå¯ä»¥è®©ç³»¾lŸçš„æ€§èƒ½æ›´å¥½ã€‚但事实果真如æ¤å—?我对æ¤å˜ç–‘ã€?/p>
首先我们‹‚€æŸ¥ä¸€ä¸‹é¥¿æ±‰å’Œæ‡’汉å•ä¾‹æ¨¡å¼æœ€½Ž€å•的写法åQˆè¿™é‡Œä¸è®¨è®ºå“ªç§æ‡’汉写法更好åQ‰ï¼š
// 饿汉 public final class HungrySingleton { private static final HungrySingleton INSTANCE = new HungrySingleton(); private HungrySingleton() { System.out.println("Initializing..."); } public static HungrySingleton getInstance() { return INSTANCE; } } // 懒汉 public final class LazySingleton { private static LazySingleton INSTANCE; private LazySingleton() { System.out.println("Initializing..."); } public static synchronized LazySingleton getInstance() { if (INSTANCE == null) { INSTANCE = new LazySingleton(); } return INSTANCE; } }
从ç†è®ÞZ¸Šæ¥è¯´åQ?code>HungrySingleton çš„å•例在该类½W¬ä¸€‹Æ¡ä‹É用的时候创建,è€?LazySingleton
çš„å•例则在其 getInstance()
æ–ÒŽ³•被调用的时候创建。至于网上有人声¿U°â€œé¥¿æ±‰å¼ä¸ç®¡ç”¨ä¸ç”¨éƒ½ä¼šåˆå§‹åŒ–â€ï¼Œ¾U¯å±žèµ°èµ\的时候æ¥å迈得太大。è°çš„åŠ è½½æ›´˜qŸï¼Ÿå¦‚æžœä½ åªæ˜¯è°ƒç”¨å®ƒä»¬çš„ getInstance()
æ–ÒŽ³•æ¥å¾—到å•例对象,则它们都是åšg˜qŸåŠ è½½ï¼Œ˜q™æ ·æ‡’æ±‰å¼æ²¡æœ‰ä“Q何æ„义,而且ç”׃ºŽ LazySingleton
采å–äº†åŒæ¥æŽªæ–½ï¼Œæ€§èƒ½æ›´ä½ŽåQˆå¯ä»¥è¯´ä»ÖM½•懒汉å¼çš„æ€§èƒ½éƒ½ä½ŽäºŽé¥¿æ±‰å¼åQ‰ã€‚å½“ä½ ä‹É用一个å•例类的时候,éšùN“½W¬ä¸€æ¥ä¸æ˜¯è°ƒç”?getInstance()
么?所以在自己的代ç 里åQŒæˆ‘æ›´å–œ‹Æ¢ç”¨é¥¿æ±‰å¼ã€?/p>
下é¢ç”¨ä¸€ä¸ªä¾‹å楋¹‹è¯•åŠ è²™åºåºåQ?/p>
// 饿汉 System.out.println("Before"); HungrySingleton.getInstance(); System.out.println("After"); // 懒汉 System.out.println("Before"); LazySingleton.getInstance(); System.out.println("After");
输出¾l“果都是åQ?/p>
Before Initializing... After
那么åQŒæ‡’汉模å¼è¿˜æœ‰ä»€ä¹ˆå˜åœ¨æ„义?如果¾pÈ»Ÿä½¿ç”¨äº†æŸäº›éœ€è¦åœ¨å¯åŠ¨æ—¶å¯¹¾c»è¿›è¡Œæ‰«æçš„æ¡†æž¶åQŒä‹É用饿汉å¼çš„è¯åQŒå¯åŠ¨æ—¶é—´æ¯”æ‡’æ±‰å¼æ›´é•¿ï¼Œå¦‚果使用了大é‡å•例类åQŒä¸åˆ©äºŽå¼€å‘阶ŒDüc€‚在¾pÈ»Ÿçš„æ£å¼è¿è¡Œé˜¶ŒDµï¼Œæ‰€æœ‰çš„å•例¾c»è¿Ÿæ—©éƒ½è¦åŠ è½½çš„åQŒæ€Èš„说æ¥ä¸¤è€…性能æŒåã^åQŒä½†æ˜¯æ‡’æ±‰å¼æ¯æ¬¡éƒ½è‡³ž®‘多一个判æ–ï¼Œæ‰€ä»¥è¶Šåˆ°åŽæœŸè¶Šä½“现饿汉的优‘Šæ€§ã€?/p>
最åŽï¼ŒæŽ¨è下《Effective Java》第二版指出的用枚ä‹D¾cÕdž‹å®žçŽ°çš„é¥¿æ±‰å•例模å¼ï¼š
// 饿汉 public enum HungrySingleton { INSTANCE; private HungrySingleton() { } }
˜q™ç§å†™æ³•ä¸ä½†æœ€½Ž€‹z,˜q˜èƒ½è½ÀL˜“扩展为实例数é‡å›ºå®šçš„“多例模å¼â€ã€?/p>
JDK æä¾›äº†å¯¹ TCPåQˆTransmission Control ProtocolåQŒä¼ 输控制å议)å’?UDPåQˆUser Datagram ProtocolåQŒç”¨æˆäh•°æ®æŠ¥åè®®åQ‰è¿™ä¸¤ä¸ªæ•°æ®ä¼ 输å议的支æŒã€‚本文开始探è®?TCPã€?/p>
在“æœåС噍-客户端â€è¿™¿Uæž¶æž„ä¸åQŒæœåŠ¡å™¨å’Œå®¢æˆïL«¯å„自¾l´æŠ¤ä¸€ä¸ªç«¯ç‚¹ï¼Œä¸¤ä¸ªç«¯ç‚¹éœ€è¦é€šè¿‡¾|‘络˜q›è¡Œæ•°æ®äº¤æ¢ã€‚TCP 䏸™¿™¿U需求æä¾›äº†ä¸€¿Uå¯é çš„‹¹å¼˜qžæŽ¥åQŒæµå¼çš„æ„æ€æ˜¯ä¼ 出和收到的数æ®éƒ½æ˜¯˜qžç®‹çš„å—节,没有å¯ÒŽ•°æ®é‡˜q›è¡Œå¤§å°é™åˆ¶ã€‚一个端点由 IP 地å€å’Œç«¯å£æž„æˆï¼ˆä¸“业术è¯ä¸ºâ€œå…ƒ¾l?{IP 地å€, 端å£}
â€ï¼‰ã€‚è¿™æ øP¼Œä¸€ä¸ªè¿žæŽ¥å°±å¯ä»¥ç”±å…ƒ¾l?{本地地å€, 本地端å£, ˜qœç¨‹åœ°å€, ˜qœç¨‹ç«¯å£}
æ¥è¡¨½Cºã€?/p>
åœ?TCP ¾~–程接å£ä¸ï¼Œç«¯ç‚¹ä½“现ä¸?TCP 套接å—。共有两¿U?TCP 套接å—:ä¸ÕdŠ¨å’Œè¢«åŠ¨ï¼Œâ€œè¢«åŠ¨â€çжæ€ä¹Ÿå¸¸è¢«¿UîCؓ“侦å¬â€çжæ€ã€‚æœåŠ¡å™¨å’Œå®¢æˆïL«¯åˆ©ç”¨å¥—接å—进行连接的˜q‡ç¨‹å¦‚下åQ?/p>
䏋颿˜¯è¿žæŽ¥è¿‡½E‹çš„图解åQ?/p>
TCP ˜qžæŽ¥
JDK æä¾›äº?ServerSocket
¾cÀL¥ä»£è¡¨ TCP æœåŠ¡å™¨çš„è¢«åŠ¨å¥—æŽ¥å—。下é¢çš„ä»£ç æ¼”示了一个简å•çš„ TCP æœåŠ¡å™¨ï¼ˆå¤šçº¿½E‹é˜»å¡žæ¨¡å¼ï¼‰åQŒå®ƒä¸æ–侦å¬òq¶æŽ¥å—客æˆïL«¯çš„连接,然厞®†å®¢æˆïL«¯å‘é€è¿‡æ¥çš„æ–‡æœ¬æŒ‰è¡Œè¯Õd–åQŒå…¨æ–‡è{æ¢äؓ大写åŽè¿”回给客户端,直到客户端å‘逿–‡æœ¬è¡Œ bye
åQ?/p>
public class TcpServer implements Runnable { private ServerSocket serverSocket; public TcpServer(int port) throws IOException { // 创徾l‘定到æŸä¸ªç«¯å£çš„ TCP æœåŠ¡å™¨è¢«åŠ¨å¥—æŽ¥å—ã€? serverSocket = new ServerSocket(port); } @Override public void run() { while (true) { try { // ä»¥é˜»å¡žçš„æ–¹å¼æŽ¥å—一个客æˆïL«¯˜qžæŽ¥åQŒè¿”回代表该˜qžæŽ¥çš„主动套接å—ã€? Socket socket = serverSocket.accept(); // 在新¾U¿ç¨‹ä¸å¤„ç†å®¢æˆïL«¯˜qžæŽ¥ã€? new Thread(new ClientHandler(socket)).start(); } catch (IOException ex) { ex.printStackTrace(); } } } } public class ClientHandler implements Runnable { private Socket socket; public ClientHandler(Socket socket) { this.socket = Objects.requireNonNull(socket); } @Override public void run() { try (Socket s = socket) { // å‡å°‘代ç é‡çš„花招…â€? // 包装套接å—的输入‹¹ä»¥è¯Õd–客户端å‘é€çš„æ–‡æœ¬è¡Œã€? BufferedReader in = new BufferedReader(new InputStreamReader( s.getInputStream(), StandardCharsets.UTF_8)); // 包装套接å—的输出‹¹ä»¥å‘客æˆïL«¯å‘é€è{æ¢ç»“æžœã€? PrintWriter out = new PrintWriter(new OutputStreamWriter( s.getOutputStream(), StandardCharsets.UTF_8), true); String line = null; while ((line = in.readLine()) != null) { if (line.equals("bye")) { break; } // ž®†è{æ¢ç»“果输出给客户端ã€? out.println(line.toUpperCase(Locale.ENGLISH)); } } catch (IOException ex) { ex.printStackTrace(); } } }
é˜Õd¡žæ¨¡å¼çš„ç¼–½E‹æ–¹å¼ç®€å•,但å˜åœ¨æ€§èƒ½é—®é¢˜åQŒå› 为æœåС噍¾U¿ç¨‹ä¼šå¡æÕdœ¨æŽ¥å—客户端的 accept()
æ–ÒŽ³•上,ä¸èƒ½æœ‰æ•ˆåˆ©ç”¨èµ„æºã€‚å¥—æŽ¥å—æ”¯æŒéžé˜»å¡žæ¨¡å¼ï¼ŒçŽ°åœ¨æš‚æ—¶ç•¥è¿‡ã€?/p>
JDK æä¾›äº?Socket
¾cÀL¥ä»£è¡¨ TCP 客户端的ä¸ÕdŠ¨å¥—æŽ¥å—。下é¢çš„ä»£ç æ¼”示了上˜q°æœåŠ¡å™¨çš„å®¢æˆïL«¯åQ?/p>
public class TcpClient implements Runnable { private Socket socket; public TcpClient(String host, int port) throws IOException { // 创徘qžæŽ¥åˆ°æœåŠ¡å™¨çš„å¥—æŽ¥å—ã€? socket = new Socket(host, port); } @Override public void run() { try (Socket s = socket) { // 冿¬¡å‡å°‘代ç é‡â€¦â€? // 包装套接å—的输出‹¹ä»¥å‘æœåС噍å‘逿–‡æœ¬è¡Œã€? PrintWriter out = new PrintWriter(new OutputStreamWriter( s.getOutputStream(), StandardCharsets.UTF_8), true); // 包装套接å—的输入‹¹ä»¥è¯Õd–æœåŠ¡å™¨è¿”å›žçš„æ–‡æœ¬è¡Œã€? BufferedReader in = new BufferedReader(new InputStreamReader( s.getInputStream(), StandardCharsets.UTF_8)); Console console = System.console(); String line = null; while ((line = console.readLine()) != null) { if (line.equals("bye")) { break; } // ž®†æ–‡æœ¬è¡Œå‘é€ç»™æœåС噍ã€? out.println(line); // æ‰“å°æœåŠ¡å™¨è¿”å›žçš„æ–‡æœ¬è¡Œã€? console.writer().println(in.readLine()); } // 通知æœåС噍关é—连接ã€? out.println("bye"); } catch (IOException ex) { ex.printStackTrace(); } } }
ä»?JDK 文档å¯ä»¥çœ‹åˆ°åQ?code>ServerSocket å’?Socket
在åˆå§‹åŒ–的时候,å¯ä»¥è®‘Ö®šä¸€äº›å‚敎ͼŒ˜q˜æ”¯æŒåšg˜qŸç»‘定。这些东西对性能和行为都有所影å“。下一½‹‡æ–‡ç« 将详解˜q™ä¸¤ä¸ªç±»çš„åˆå§‹åŒ–ã€?/p>
我竟然到现在æ‰å‘现《Fundamental Networking in Java》这本神作,真有ç‚ÒŽ— 地自容的感觉。最˜q‘å‡ òq´åšçš„都是所谓的ä¼ä¸š¾U§å¼€å‘,å…ä¸äº†å’Œ¾|‘络打交é“,但在实际工作ä¸ï¼Œå¾€å¾€ä¼šé‡‡ç”¨æ¡†æž¶å°†åº•层¾l†èŠ‚å’Œä¸Šå±‚åº”ç”¨éš”¼›Õd¼€åQŒæ„Ÿè§‰å°±åƒæ˜¯åœ¨ä¸€ä¸?Word 模æ¿è¡¨å•里é¢å¡«å†™å†…容åQŒåšå‡ºæ¥ä¹Ÿæ²¡ä»€ä¹ˆæˆž®±æ„Ÿã€‚虽然没有ä¸ä½¿ç”¨æ¡†æž¶çš„ç†ç”±ï¼Œä½†æˆ‘˜q˜çœŸæ˜¯æœ‰ç‚ÒŽ€€å¿µå½“åˆç›´æŽ¥ç”¨å¥—接å—åš¾|‘络¾~–程的日å,既能掌控更多东西åQŒè¿˜å¯ä»¥å¦åˆ°æ›´å¤šçŸ¥è¯†åQŒäØ“ç ”ç©¶æ¡†æž¶çš„å®žçŽ°åŽŸç†æ‰“基础。闲è¯å®Œæ¯•,转入今天的æ£é¢˜ï¼šIPåQˆInternet ProtocolåQŒäº’è”网åè®®åQ‰ã€?/p>
说到 IPåQŒå¤§å¤šæ•°äººçš„½W¬ä¸€å应估计都是 IP 地å€ã€‚å…¶å®?IP 是一¿Uå议,IP 地å€åªæ˜¯å议的一部分。《RFC 791 - INTERNET PROTOCOL》说åQšâ€œäº’è”网åè®®æ˜¯äØ“åœ¨åŒ…äº¤æ¢è®¡ç®—机通信¾|‘络的互è”ç³»¾lŸä¸ä½¿ç”¨è€Œè®¾è®¡çš„。â€IP 包å«ä¸‰æ–¹é¢çš„功能åQ?/p>
ä»?Java 的角度æ¥çœ‹ä¸Šé¢è¯´åˆ°çš„三个功能åQŒåªæœ‰ç¬¬ä¸€ä¸ªæ˜¯å¼€å‘äh员需è¦å…³å¿ƒçš„。å¦å¤–两个都ä¾èµ–底层¾pÈ»Ÿçš„实玎ͼŒJDK 也没有æä¾›ç›¸å…³çš„¾cÕdŽ»æ“作。下é¢ä¸€ä¸€ä»‹ç» JDK æä¾›çš„用于处ç?IP 地å€çš„ç±»ã€?/p>
æ¤ç±»ç”¨æ¥è¡¨ç¤º IP 地å€åQŒå®ƒæœ‰ä¸¤ä¸ªå¾c»ï¼šInet4Address
å’?Inet6Address
åQŒåˆ†åˆ«ç”¨äºŽå¤„ç?IPv4 å’?IPv6 两个版本。在实际应用ä¸ï¼ŒInetAddress
‘³ä»¥åº”付¾l大多数情况。它æä¾›äº†ä¸€äº›é™æ€æ–¹æ³•æ¥æž„é€ å®žä¾‹ï¼Œèƒ½æ ¹æ®å‚æ•°æ ¼å¼è‡ªåŠ¨è¯†åˆ?IP 版本åQ?/p>
public static InetAddress[] getAllByName(String host) throws UnknownHostException
public static InetAddress getByAddress(byte[] addr) throws UnknownHostException
public static InetAddress getByAddress(String host, byte[] addr) throws UnknownHostException
public static InetAddress getByName(String host) throws UnknownHostException
getAllByName(host)[0]
�/dd>
public static InetAddress getLocalHost() throws UnknownHostException
public static InetAddress getLoopbackAddress()
127.0.0.1
åQŒä¸æŠ›å‡ºå¼‚常åQŒç‰åŒäºŽ getByName("localhost")
åQˆä¸è¦å’Œ getLocalHost()
æžæØœåQ‰ã€‚环回地å€ä½¿ä¸»æœø™ƒ½å¤Ÿè‡ªå·Þp¿žæŽ¥è‡ªå·±ï¼Œå¸¸è¢«ç”¨æ¥å¯¹åœ¨åŒä¸€å°æœºå™¨ä¸Š‹¹‹è¯•¾|‘络应用½E‹åºã€‚在 IPv4 ä¸ï¼ŒçŽ¯å›žåœ°å€çš„网ŒDµäØ“ 127.0.0.0/8
åQŒé€šå¸¸ç”?127.0.0.1
åQ›IPv6 ä¸åªæœ‰ä¸€ä¸?::1
�/dd>
接下æ¥çœ‹çœ?InetAddress
ä¸å®šä¹‰çš„部分实例æ–ÒŽ³•åQ?/p>
public byte[] getAddress()
public String getCanonicalHostName()
InetAddress.getByName("www.google.com").getCanonicalHostName()
˜q”回 we-in-f99.1e100.netã€?/dd>
public String getHostAddress()
public String getHostName()
getCanonicalHostName()
åQŒå¦åˆ™ç›´æŽ¥è¿”å›žæž„é€ æ—¶ä¼ å…¥çš„ä¸»æœºåœ°å€ã€?/dd>
public boolean isAnyLocalAddress()
0.0.0.0
åQˆIPv4åQ‰æˆ– ::0
åQˆIPv6åQ‰ï¼Œä»£è¡¨æ‰€æœ‰çš„æœ¬åœ° IP 地å€ã€‚例如,å‡è®¾ç”µè„‘有两å—网å¡ï¼Œå„有一个地å€åQŒå¦‚果想让一个程åºåŒæ—¶ç›‘å¬è¿™ä¸¤ä¸ªåœ°å€åQŒå°±éœ€è¦ç”¨é€šé…½W¦åœ°å€ã€?/dd>
public boolean isLinkLocalAddress()
169.254.0.0/16
åQŒIpv6 里是ä»?fe80::/64
为剾~€çš„地å€ã€‚在电脑没蔾|‘的时候查看本æœ?IPåQŒå°±èƒ½çœ‹åˆ°è¿™¿U地å€ã€?/dd>
public boolean isLoopbackAddress()
public boolean isSiteLocalAddress()
fc00::/7
。这些地å€ç”¨äºŽ¿U有¾|‘络åQŒä¾‹å¦‚ä¼ä¸šå†…部的局域网ã€?/dd>
æ¤å¤–˜q˜æœ‰ä¸€äº›æœ‰å…›_¤šæ’地å€çš„æ–¹æ³•,暂时略过ã€?/p>
JDK é»˜è®¤åŒæ—¶æ”¯æŒ IPv4 å’?IPv6ã€‚å¦‚æžœåªæƒ³ä‹É用一¿U,å¯ä»¥æ ÒŽ®æƒ…况ž®?java.net.preferIPv4Stack
�java.net.preferIPv6Addresses
˜q™ä¸¤ä¸ªç³»¾lŸå±žæ€§ä¹‹ä¸€è®¾äØ“ true
。两个属性的默认值都�false
。一般æ¥è¯´ä¸éœ€è¦åŽ»æƒŠåŠ¨å®ƒä»¬ã€?/p>
该类是一个空壻I¼Œäº‹å®žä¸Šåº”用程åºä‹É用的是它的唯一åç±» InetSocketAddress
åQŒç›®å‰è¿˜çœ‹ä¸å‡ø™¿™æ ¯‚®¾è®¡æœ‰ä»€ä¹ˆæ„义。该¾cÕdªä¸è¿‡åœ?InetAddress
的基¼‹€ä¸Šå¢žåŠ äº†ä¸€ä¸ªç«¯å£å±žæ€§ã€?/p>
该类代表¾|‘络接å£åQŒä¾‹å¦‚一å—网å¡ã€‚一个网¾lœæŽ¥å£å¯ä»¥ç»‘定一äº?IP 地å€ã€‚具有多个网¾lœæŽ¥å£çš„ä¸ÀLœºè¢«ç§°ä¸ºå¤šå®¿ä¸»ä¸ÀLœºã€‚下é¢çš„代ç 坿‰“å°å‡ºæ‰€æœ‰æœ¬æœºç½‘¾lœæŽ¥å£çš„ä¿¡æ¯åQ?/p>
for (NetworkInterface ni : Collections.list(NetworkInterface.getNetworkInterfaces())) { System.out.println(ni); for (InterfaceAddress ia : ni.getInterfaceAddresses()) { System.out.println("\t" + ia); } System.out.println(); }
在我的笔记本上è¿è¡Œç»“æžœäØ“åQ?/p>
name:lo (Software Loopback Interface 1) /127.0.0.1/8 [/127.255.255.255] /0:0:0:0:0:0:0:1/128 [null] name:net0 (WAN Miniport (SSTP)) name:net1 (WAN Miniport (L2TP)) name:net2 (WAN Miniport (PPTP)) name:ppp0 (WAN Miniport (PPPOE)) name:eth0 (WAN Miniport (IPv6)) name:eth1 (WAN Miniport (Network Monitor)) name:eth2 (WAN Miniport (IP)) name:ppp1 (RAS Async Adapter) name:net3 (WAN Miniport (IKEv2)) name:net4 (Intel(R) Wireless WiFi Link 4965AGN) /fe80:0:0:0:288a:2daf:3549:1811%11/64 [null] name:eth3 (Broadcom NetXtreme 57xx Gigabit Controller) /10.140.1.133/24 [/10.140.1.255] /fe80:0:0:0:78c7:e420:1739:f947%12/64 [null] name:net5 (Teredo Tunneling Pseudo-Interface) /fe80:0:0:0:e0:0:0:0%13/64 [null] name:net6 (Bluetooth Device (RFCOMM Protocol TDI)) name:eth4 (Bluetooth Device (Personal Area Network)) name:eth5 (Cisco AnyConnect VPN Virtual Miniport Adapter for Windows x64) name:net7 (Microsoft ISATAP Adapter) /fe80:0:0:0:0:5efe:a8c:185%17/128 [null] name:net8 (Microsoft ISATAP Adapter #2) name:net9 (Intel(R) Wireless WiFi Link 4965AGN-QoS Packet Scheduler-0000) name:eth6 (Broadcom NetXtreme 57xx Gigabit Controller-TM NDIS Sample LightWeight Filter-0000) name:eth7 (Broadcom NetXtreme 57xx Gigabit Controller-QoS Packet Scheduler-0000) name:eth8 (Broadcom NetXtreme 57xx Gigabit Controller-WFP LightWeight Filter-0000) name:eth9 (WAN Miniport (Network Monitor)-QoS Packet Scheduler-0000) name:eth10 (WAN Miniport (IP)-QoS Packet Scheduler-0000) name:eth11 (WAN Miniport (IPv6)-QoS Packet Scheduler-0000) name:net10 (Intel(R) Wireless WiFi Link 4965AGN-Native WiFi Filter Driver-0000) name:net11 (Intel(R) Wireless WiFi Link 4965AGN-TM NDIS Sample LightWeight Filter-0000) name:net12 (Intel(R) Wireless WiFi Link 4965AGN-WFP LightWeight Filter-0000)
Exchanger
用æ¥è®©ä¸¤ä¸ªçº¿½E‹äº’相ç‰å¾…åÆˆäº¤æ¢è®¡ç®—¾l“果。这个类的用法很½Ž€å•ï¼Œå› äØ“å®ƒå°±å®šä¹‰äº†ä¸¤ä¸ªé‡è½½çš„ exchange
æ–ÒŽ³•åQŒå‚æ•°å¤šçš„é‚£ä¸ªæ— éžå¢žåŠ äº†å¯¹è¶…æ—¶çš„æ”¯æŒã€‚当一个线½E‹è°ƒç”?exchange
的时候(以计½Ž—ç»“æžœä½œä¸ºå‚æ•ŽÍ¼‰åQŒå®ƒž®±å¼€å§‹ç‰å¾…å¦ä¸€ä¸ªçº¿½E‹è°ƒç”?exchange
åQŒç„¶åŽä¸¤ä¸ªçº¿½E‹åˆ†åˆ«æ”¶åˆ°å¯¹æ–¹è°ƒç”?exchange
æ—¶ä¼ å…¥çš„å‚æ•°åQŒä»Žè€Œå®Œæˆäº†è®¡ç®—¾l“果的交æ¢ã€?/p>
ä¸ç”¨å¤ªå¤šçš„解释,˜q行下题q™ä¸ªä¾‹åž®×ƒ¸€æ¸…二楚:
final Exchanger<String> e = new Exchanger<>(); new Thread() { @Override public void run() { long id = Thread.currentThread().getId(); String s = "abc"; System.out.println("¾U¿ç¨‹ [" + id + "] ½Ž—出 " + s); try { TimeUnit.SECONDS.sleep(new Random().nextInt(5)); System.out.println("¾U¿ç¨‹ [" + id + "] 收到 " + e.exchange(s)); } catch (InterruptedException ex) { ex.printStackTrace(); } } }.start(); new Thread() { @Override public void run() { long id = Thread.currentThread().getId(); String s = "xyz"; System.out.println("¾U¿ç¨‹ [" + id + "] ½Ž—出 " + s); try { TimeUnit.SECONDS.sleep(new Random().nextInt(5)); System.out.println("¾U¿ç¨‹ [" + id + "] 收到 " + e.exchange(s)); } catch (InterruptedException ex) { ex.printStackTrace(); } } }.start();
˜q行¾l“æžœåQˆå¯èƒ½äØ“åQ‰ï¼š
¾U¿ç¨‹ [9] ½Ž—出 abc ¾U¿ç¨‹ [10] ½Ž—出 xyz ¾U¿ç¨‹ [10] 收到 abc ¾U¿ç¨‹ [9] 收到 xyz
最åŽå¼ºè°ƒä¸‹åQŒè¯¥¾cÕdªé€‚用于两个线½E‹ï¼Œå¦„图用它æ¥å¤„ç†å¤šä¸ªç”Ÿäº§è€…和消费者之间的数æ®äº¤æ¢æ˜¯æ³¨å®šè¦å¤ÞpÓ|的…â€?/p>
以剿ˆ‘曾用两个类åQ?a >ZipItem
å’?ZipSystem
åQ‰å®žçŽîCº†ä¸€ä¸ªç®€å•çš„ ZIP æ–‡äšg¾pÈ»ŸåQˆä»¥ä¸‹ç®€¿U?ZFSåQ‰ã€‚其实这两个ž®ç±»æŒºå¥½ç”¨çš„åQŒè€Œä¸”支æŒåµŒå¥—çš?ZIP æ–‡äšgåQŒä½†æ˜¯ï¼Œä½†æ˜¯â€¦â€¦JDK 7 丢下æ¥ä¸€æžšå«å?NIO2 çš„ç¬‘æ°”ç‚¸å¼¹ï¼Œå¼•å…¥äº†ä¸€å¥—æ ‡å‡†çš„æ–‡äšg¾pÈ»Ÿ APIåQŒæˆ‘承认我ä¸å¼¹äº†åQŒæ‰‹ç—’了åQŒåˆæ ÒŽ®˜q™å¥— API 釿–°å®žçްäº?ZIP æ–‡äšg¾pÈ»ŸåQŒç»ˆäºŽåœ¨ä»Šå¤©åˆæ¥å®Œå·¥åQŒå“ˆã€?/p>
è¯è¯´åQŒJDK 7 其实æ†ç»‘销售了一ä¸?ZFSåQŒdemo 目录下还有æºä»£ç 。å¯â€¦â€¦å®ƒè¾¾ä¸åˆ°æˆ‘的奢求,而且 BUG ä¸å°‘。éšä¾‰K€®ä¸¤ä¸ªï¼š
// com.sun.nio.zipfs.ZipFileSystemProvider ¾cÖM¸çš„æ–¹æ³? @Override public Path getPath(URI uri) { String spec = uri.getSchemeSpecificPart(); int sep = spec.indexOf("!/"); if (sep == -1) throw new IllegalArgumentException("URI: " + uri + " does not contain path info ex. jar:file:/c:/foo.zip!/BAR"); // 难怪该æ–ÒŽ³•始终æŠ?IllegalArgumentException 异常åQŒåŽŸæ¥ä½ ž®å把文件的 URI // å½“æˆ ZFS çš?URI 在用…â€? return getFileSystem(uri).getPath(spec.substring(sep + 1)); } // com.sun.nio.zipfs.ZipFileSystem ¾cÖM¸çš„æ–¹æ³? @Override public PathMatcher getPathMatcher(String syntaxAndInput) { int pos = syntaxAndInput.indexOf(':'); // 丫的åQŒpos == syntaxAndInput.length()åQŸï¼è°å†™çš„?抓出æ¥éžž®¸ã€? if (pos <= 0 || pos == syntaxAndInput.length()) { throw new IllegalArgumentException();
很明显,官方 ZFS 没有¾l过代ç å®¡é˜…ã€æ²¡æœ‰ç»˜q‡æµ‹è¯•ã€æ²¡æœ‰ç»˜q‡â€¦â€¦ç„¶åŽï¼Œ@author Xueming Shen
åQŒçœŸæ˜¯ä¸¢å’±åŽå¤æ°‘æ—的脸…â€?/p>
下é¢åˆ—ä¸ªè¡¨æ ¼è¯¦ç»†æ¯”è¾ƒå®˜æ–¹ ZFS 和山å¯?ZFSåQ?/p>
比较内容 | 官方 ZFS | 山寨 ZFS |
å®žçŽ°æ–¹å¼ | å¦è“v炉ç¶åQŒç”¨¾U?Java 釿–°å®žçŽ°äº†å¯¹ ZIP æ–‡äšgæ ¼å¼çš„处ç†ä»£ç ã€?/td> | åŸÞZºŽ ZipFile å’?ZipInputStream ˜q™ä¸¤ä¸ªå·²¾l稳定多òq´çš„¾c»ï¼Œä½†æ¶‰åŠäº†å¤§é‡æœ¬åœ°ä»£ç 调用åQŒä¹Ÿè®æ€¼šå½±å“性能ã€?/td>
|
è¯ÀL“ä½?/td> | 支æŒåQŒä¸”通过解压åˆîCÍæ—¶æ–‡ä»¶æ”¯æŒéšæœø™®¿é—®ã€?/td> | 支æŒåQŒä½†ä¸æ”¯æŒéšæœø™®¿é—®ã€?/td> |
写æ“ä½?/td> | 通过解压åˆîCÍæ—¶æ–‡ä»¶è¿›è¡Œæ”¯æŒï¼Œä½†æ— 法检‹¹‹åˆ°å…¶ä»–˜q›ç¨‹å¯¹åŒä¸€ä¸?ZIP æ–‡äšg的写æ“作åQŒä¸é€‚ç”¨äºŽåÆˆå‘环境ã€?/td> | 䏿”¯æŒã€‚ZIP æ–‡äšg事实上是一个整体,对内部æ¡ç›®çš„ä»ÖM½•修改都å¯èƒ½å¯¼è‡´é‡æž„整个文ä»Óž¼Œå› æ¤æ‰€è°“的写æ“作必™å»é€šè¿‡ä¸´æ—¶æ–‡äšgæ¥å¤„ç†ï¼Œæ•ˆçŽ‡ä½Žä¸‹åQŒæ„义ä¸å¤§ï¼Œè€Œä¸”难以处ç†åµŒå¥— ZIP æ–‡äšgã€‚è¿™ä¹Ÿç¬¦åˆæˆ‘的原则:ä¸è§£åŽ‹ã€?/td> |
嵌套 ZIP æ–‡äšg | 䏿”¯æŒã€?/td> | 支æŒåQŒå½“然读å–嵌å¥?ZIP æ–‡äšg会慢一些ã€?/td> |
åæ–œ¾U¿åˆ†éš”符 | 䏿”¯æŒï¼Œç›´æŽ¥ç“œæŽ‰ã€?/td> | 支æŒåQŒä¸”å’Œæ ‡å‡†çš„æ–œçº¿åˆ†éš”½W¦åŒºåˆ«å¯¹å¾…。例如,/abc/ å’?/abc\ ½Ž—ä¸åŒçš„æ–‡äšgåQŒå®žé™…上˜q™ä¸¤ä¸ªèƒ½å¤Ÿåƈå˜äºŽ ZIP æ–‡äšgä¸ã€?/td>
|
½Iºç›®å½•å | 䏿”¯æŒï¼Œç›´æŽ¥ç“œæŽ‰ã€?/td> | 支æŒã€‚例å¦?/a/b å’?/a//b 是两个å¯ä»¥åƈå˜ä¸”ä¸åŒçš„æ–‡ä»¶ã€?/td>
|
山寨 ZFS 的用法示例:
Map<String, Object> env = new HashMap<>(); // 用于解ç ZIP æ¡ç›®åã€‚é»˜è®¤äØ“ Charset.defaultCharset()ã€? env.put("charset", StandardCharsets.UTF_8); // 指示是å¦è‡ªåŠ¨æŽ¢æµ‹åµŒå¥—çš?ZIP æ–‡äšgã€‚é»˜è®¤äØ“ falseã€? env.put("autoDetect", true); // 默认目录åQŒç”¨äºŽåˆ›å»ºå’Œè§£æžç›¸å¯¹è·¯å¾„ã€‚é»˜è®¤äØ“â€?â€ã€? env.put("defaultDirectory", "/dir/"); // 从文件创å»ÞZ¸€ä¸?ZFSã€? try (FileSystem zfs = FileSystems.newFileSystem( URI.create("zip:" + Paths.get("docs.zip").toUri()), env)) { Path path = zfs.getPath("app.jar"); if ((Boolean) Files.getAttribute(path, "isZip")) { // 创å¾ä¸€ä¸ªåµŒå¥—çš„ ZFSã€? try (FileSystem nestedZfs = zfs.provider().newFileSystem(path, env)) { // æ¤å¤„çœç•¥è‹¥å¹²è¡Œã€? } } }
最åŽåŒæ‰‹å¥‰ä¸Šæºä»£ç åQ?a >è¯ïLŒ›å‡ÀL¤å¤„ï¼
先看出错的代ç :
public class Holder<T> { private T value; public Holder() { } public Holder(T value) { this.value = value; } public void setValue(T value) { this.value = value; } // æ¤å¤„çœç•¥è‹¥å¹²è¡Œã€? } Holder<Object> holder = new Holder<>("xxx");
看è“væ¥è¿˜å¥½ï¼Œä½†ç¼–è¯‘çš„æ—¶å€™å´æŠ¥é”™åQ?/p>
Uncompilable source code - incompatible types required: zhyi.test.Holder<java.lang.Object> found: zhyi.test.Holder<java.lang.String>
è€è€å®žå®žæŠŠ¾cÕdž‹å†™å‡ºæ¥å°±æ²¡é—®é¢˜ï¼š
Holder<Object> holder = new Holder<Object>("xxx");
如果éžè¦ç”¨é’»çŸŒ™¿½Ž—符的è¯åQŒå¯ä»¥é‡‡å–下列两¿Uæ–¹å¼ä¹‹ä¸€åQ?/p>
// ä½¿ç”¨é»˜è®¤æž„é€ å™¨åQŒå†è°ƒç”¨ setValue æ–ÒŽ³•ã€? Holder<Object> holder = new Holder<>(); holder.setValue("xxx"); // 使用泛型通酽W¦ï¼Œä½†ä¹‹åŽå°±ä¸èƒ½è°ƒç”¨ setValue 了,å¦åˆ™¾~–译出错ã€? Holder<? extends Object> holder = new Holder<>("xxx");
CyclicBarrier
的功能类ä¼égºŽå‰é¢è¯´åˆ°çš?CountDownLatch
åQŒç”¨äºŽè®©å¤šä¸ª¾U¿ç¨‹åQˆåä»ÕdŠ¡åQ‰äº’相ç‰å¾…,直到共åŒåˆ°è¾¾å…¬å…±å±éšœç‚¹ï¼ˆcommon barrier pointåQ‰ï¼Œåœ¨è¿™ä¸ªç‚¹ä¸Šï¼Œæ‰€æœ‰çš„åä“Q务都已完æˆï¼Œä»Žè€Œä¸»ä»ÕdŠ¡å®Œæˆã€?/p>
è¯¥ç±»æž„é€ çš„æ—¶å€™é™¤äº†å¿…™å»è¦æŒ‡å®š¾U¿ç¨‹æ•°é‡åQŒè¿˜å¯ä»¥ä¼ 入一ä¸?Runnable
对象åQŒå®ƒçš?run
æ–ÒŽ³•ž®†åœ¨åˆ°è¾¾å…¬å…±å±éšœç‚¹åŽæ‰§è¡Œä¸€‹Æ¡ã€‚å¾U¿ç¨‹å®Œæˆè®¡ç®—åŽï¼Œåˆ†åˆ«è°ƒç”¨ CyclicBarrier#await
æ–ÒŽ³•˜q›å…¥é˜Õd¡žçжæ€ï¼Œç›´åˆ°å…¶ä»–所有å¾U¿ç¨‹éƒ½è°ƒç”¨äº† await
�/p>
下é¢ä»ç„¶ä»¥è¿åŠ¨å‘˜å‡†å¤‡èµ›è·‘ä¸ÞZ¾‹æ¥è¯´æ˜?CyclicBarrier
的用法:
final int count = 8; System.out.println("˜q动员开始就ä½ã€?); final CyclicBarrier cb = new CyclicBarrier(count, new Runnable() { @Override public void run() { System.out.println("比赛开å§?.."); } }); for (int i = 1; i <= count; i++) { final int number = i; new Thread() { @Override public void run() { System.out.println(number + " 寂¿åŠ¨å‘˜åˆ°åœºòq¶å¼€å§‹å‡†å¤?.."); try { // 准备 2~5 ¿U’é’Ÿã€? TimeUnit.SECONDS.sleep(new Random().nextInt(4) + 2); } catch (InterruptedException ex) { } System.out.println(number + " 寂¿åŠ¨å‘˜ž®×ƒ½ã€?); try { cb.await(); } catch (InterruptedException | BrokenBarrierException ex) { } } }.start(); } System.out.println("½{‰å¾…所有è¿åŠ¨å‘˜ž®×ƒ½...");
˜q行输出åQˆå¯èƒ½ï¼‰ä¸ºï¼š
˜q动员开始就ä½ã€? 1 寂¿åŠ¨å‘˜åˆ°åœºòq¶å¼€å§‹å‡†å¤?.. 2 寂¿åŠ¨å‘˜åˆ°åœºòq¶å¼€å§‹å‡†å¤?.. ½{‰å¾…所有è¿åŠ¨å‘˜ž®×ƒ½... 3 寂¿åŠ¨å‘˜åˆ°åœºòq¶å¼€å§‹å‡†å¤?.. 4 寂¿åŠ¨å‘˜åˆ°åœºòq¶å¼€å§‹å‡†å¤?.. 6 寂¿åŠ¨å‘˜åˆ°åœºòq¶å¼€å§‹å‡†å¤?.. 8 寂¿åŠ¨å‘˜åˆ°åœºòq¶å¼€å§‹å‡†å¤?.. 5 寂¿åŠ¨å‘˜åˆ°åœºòq¶å¼€å§‹å‡†å¤?.. 7 寂¿åŠ¨å‘˜åˆ°åœºòq¶å¼€å§‹å‡†å¤?.. 1 寂¿åŠ¨å‘˜ž®×ƒ½ã€? 3 寂¿åŠ¨å‘˜ž®×ƒ½ã€? 8 寂¿åŠ¨å‘˜ž®×ƒ½ã€? 6 寂¿åŠ¨å‘˜ž®×ƒ½ã€? 2 寂¿åŠ¨å‘˜ž®×ƒ½ã€? 7 寂¿åŠ¨å‘˜ž®×ƒ½ã€? 5 寂¿åŠ¨å‘˜ž®×ƒ½ã€? 4 寂¿åŠ¨å‘˜ž®×ƒ½ã€? 比赛开å§?..
最åŽçœ‹çœ?CyclicBarrier
å’?CountDownLatch
的主è¦å¼‚åŒï¼š
Runnable
对象åQŒåœ¨ä»ÕdŠ¡å®ŒæˆåŽè‡ªåŠ¨è°ƒç”¨ï¼Œæ‰§è¡Œè€…äØ“æŸä¸ªå线½E‹ï¼›åŽè€…å¯åœ?await
æ–ÒŽ³•åŽæ‰‹åŠ¨æ‰§è¡Œä¸€ŒDµä»£ç 实现相åŒçš„功能åQŒä½†æ‰§è¡Œè€…䨓ä¸Èº¿½E‹ã€?/li>
™å‘Öæ€ä¹‰åQ?code>CountDownLatch 是一个用æ¥å€’计数的咚咚。如果柙å¹ä“Q务å¯ä»¥æ‹†åˆ†æˆè‹¥å¹²ä¸ªåä»ÕdŠ¡åŒæ—¶˜q›è¡ŒåQŒç„¶åŽç‰å¾…所有的åä“Q务完æˆï¼Œå¯ä»¥è€ƒè™‘使用它ã€?/p>
该类的用法éžå¸¸ç®€å•ã€‚é¦–å…ˆæž„é€ ä¸€ä¸?CountDownLatch
åQŒå”¯ä¸€çš„傿•°æ˜¯ä»ÕdŠ¡æ•°é‡åQŒä¸€æ—¦æž„é€ å®Œæ¯•å°±ä¸èƒ½ä¿®æ”¹ã€‚接ç€å¯åŠ¨æ‰€æœ‰çš„åä“Q务(¾U¿ç¨‹åQ‰ï¼Œä¸”æ¯ä¸ªåä»ÕdŠ¡åœ¨å®Œæˆè‡ªå·Þqš„计算åŽï¼Œè°ƒç”¨ CountDownLatch#countDown
æ–ÒŽ³•ž®†å€’计数å‡ä¸€ã€‚最åŽåœ¨ä¸Èº¿½E‹ä¸è°ƒç”¨ CountDownLatch#await
æ–ÒŽ³•½{‰å¾…计数器归零ã€?/p>
例如赛跑的准备阶ŒDµï¼Œå…«å˜q动员先åŽåˆ°è¾¾è“v点åšå¥½å‡†å¤‡ï¼Œç„¶åŽè£åˆ¤æ‰“å“å‘ä×o枪,准备工作ž®Þq»“æŸäº†åQŒæ¯”赛开始。如果把从è¿åŠ¨å‘˜ž®×ƒ½åˆ°å‘令枪å“看åšèµ›è·‘准备ä“Q务,那么æ¯ä¸ª˜q动员的准备˜q‡ç¨‹ž®±æ˜¯å…¶åä»ÕdŠ¡åQŒå¯ä»¥ç”¨ CountDownLatch
模拟如下åQ?/p>
final int count = 8; System.out.println("˜q动员开始就ä½ã€?); // æž„é€?CountDownLatchã€? final CountDownLatch cdl = new CountDownLatch(count); for (int i = 1; i <= count; i++) { final int number = i; new Thread() { @Override public void run() { System.out.println(number + " 寂¿åŠ¨å‘˜åˆ°åœºòq¶å¼€å§‹å‡†å¤?.."); try { // 让è¿åŠ¨å‘˜éšæœºå‡†å¤‡ 2~5 ¿U’é’Ÿã€? TimeUnit.SECONDS.sleep(new Random().nextInt(4) + 2); } catch (InterruptedException ex) { } System.out.println(number + " 寂¿åŠ¨å‘˜ž®×ƒ½ã€?); // 倒计数å‡ä¸€ã€? cdl.countDown(); } }.start(); } System.out.println("½{‰å¾…所有è¿åŠ¨å‘˜ž®×ƒ½..."); try { // ½{‰å¾…倒计数å˜ä¸?0ã€? cdl.await(); System.out.println("比赛开始ã€?); } catch (InterruptedException ex) { }
˜q行输出åQˆå¯èƒ½ï¼‰ä¸ºï¼š
˜q动员开始就ä½ã€? 1 寂¿åŠ¨å‘˜åˆ°åœºòq¶å¼€å§‹å‡†å¤?.. 2 寂¿åŠ¨å‘˜åˆ°åœºòq¶å¼€å§‹å‡†å¤?.. 4 寂¿åŠ¨å‘˜åˆ°åœºòq¶å¼€å§‹å‡†å¤?.. ½{‰å¾…所有è¿åŠ¨å‘˜ž®×ƒ½... 8 寂¿åŠ¨å‘˜åˆ°åœºòq¶å¼€å§‹å‡†å¤?.. 6 寂¿åŠ¨å‘˜åˆ°åœºòq¶å¼€å§‹å‡†å¤?.. 3 寂¿åŠ¨å‘˜åˆ°åœºòq¶å¼€å§‹å‡†å¤?.. 7 寂¿åŠ¨å‘˜åˆ°åœºòq¶å¼€å§‹å‡†å¤?.. 5 寂¿åŠ¨å‘˜åˆ°åœºòq¶å¼€å§‹å‡†å¤?.. 6 寂¿åŠ¨å‘˜ž®×ƒ½ã€? 1 寂¿åŠ¨å‘˜ž®×ƒ½ã€? 5 寂¿åŠ¨å‘˜ž®×ƒ½ã€? 4 寂¿åŠ¨å‘˜ž®×ƒ½ã€? 7 寂¿åŠ¨å‘˜ž®×ƒ½ã€? 8 寂¿åŠ¨å‘˜ž®×ƒ½ã€? 2 寂¿åŠ¨å‘˜ž®×ƒ½ã€? 3 寂¿åŠ¨å‘˜ž®×ƒ½ã€? 比赛开始ã€?/pre>从上é¢çš„例å˜q˜å¯ä»¥çœ‹å‡?
CountDownLatch
çš„å±€é™æ€§å’ŒCompletionService
¾cÖM¼¼åQŒåœ¨äºŽæ— 法处ç†åä»ÕdŠ¡æ•°é‡ä¸ç¡®å®šçš„æƒ…况åQŒä¾‹å¦‚统计æŸä¸ªæ–‡ä»¶å¤¹ä¸çš„æ–‡äšgæ•°é‡ã€‚å¦å¤–,如果æŸä¸ªåä“Q务在调用countDown
之剞®±æŒ‚掉了åQŒå€’计数就永远ä¸ä¼šå½’零。对于这¿U情况,è¦ä¹ˆç”?finally
之类的手ŒDµä¿è¯?countDown
一定会被调用,è¦ä¹ˆç”¨å¸¦å‚æ•°çš?await
æ–ÒŽ³•指定‘…æ—¶æ—‰™—´ã€?/p>蜀山兆å¨é¾˜ 2011-10-14 14:22 å‘表评论]]>
CompletionService
接å£çš„实例å¯ä»¥å……当生产者和消费者的ä¸é—´å¤„ç†å¼•擎åQŒä»Žè€Œè¾¾åˆ°å°†æäº¤ä»ÕdŠ¡å’Œå¤„ç†ç»“æžœçš„ä»£ç ˜q›è¡Œè§£è€¦çš„目的。生产者调ç”?submit
æ–ÒŽ³•æäº¤ä»ÕdŠ¡åQŒè€Œæ¶ˆè´¹è€…è°ƒç”?poll
åQˆéžé˜Õd¡žåQ‰æˆ– take
åQˆé˜»å¡žï¼‰æ–ÒŽ³•获å–下一个结果:˜q™ä¸€ç‰¹å¾çœ‹è“væ¥å’Œé˜Õd¡žé˜Ÿåˆ—åQ?code>BlockingQueueåQ‰ç±»ä¼û|¼Œä¸¤è€…的区别在于 CompletionService
è¦è´Ÿè´£ä“Q务的处ç†åQŒè€Œé˜»å¡žé˜Ÿåˆ—则ä¸ä¼šã€?/p>
åœ?JDK ä¸ï¼Œè¯¥æŽ¥å£åªæœ‰ä¸€ä¸ªå®žçŽ°ç±» ExecutorCompletionService
åQŒè¯¥¾cÖM‹É用创建时æä¾›çš?Executor
对象åQˆé€šå¸¸æ˜¯çº¿½E‹æ± åQ‰æ¥æ‰§è¡Œä»ÕdŠ¡åQŒç„¶åŽå°†¾l“果攑օ¥ä¸€ä¸ªé˜»å¡žé˜Ÿåˆ—ä¸åQšæžœç„¶æœ¬ž®±æ˜¯ä¸€å®¶äº²å•Šï¼ExecutorCompletionService
ž®†çº¿½E‹æ± 和阻塞队列糅åˆåœ¨ä¸€èµøP¼Œä»…仅通过三个æ–ÒŽ³•åQŒå°±å®žçŽ°äº†ä“Q务的异æ¥å¤„ç†åQŒå¯è°“åÆˆå‘ç¼–½E‹åˆå¦è€…çš„¼œžå…µåˆ©å™¨åQ?/p>
接下æ¥çœ‹ä¸€ä¸ªä¾‹å。楼ä¸ÀLœ‰ä¸€å¤§å † *.java æ–‡äšgåQŒéœ€è¦è®¡½Ž—å®ƒä»¬çš„ä»£ç æ€»è¡Œæ•°ã€‚利ç”?ExecutorCompletionService
å¯ä»¥å†™å‡ºå¾ˆç®€å•的多线½E‹å¤„ç†ä»£ç :
public int countLines(List<Path> javaFiles) throws Exception { // æ ÒŽ®å¤„ç†å™¨æ•°é‡åˆ›å»ºçº¿½E‹æ± 。虽然多¾U¿ç¨‹òq¶ä¸ä¿è¯èƒ½å¤Ÿæå‡æ€§èƒ½åQŒä½†é€‚é‡åœ? // å¼€¾U¿ç¨‹ä¸€èˆ¬å¯ä»¥ä»Ž¾pÈ»Ÿéª—å–æ›´å¤šèµ„æºã€? ExecutorService es = Executors.newFixedThreadPool( Runtime.getRuntime().availableProcessors() * 2); // 使用 ExecutorCompletionService 内å¾çš„阻塞队列ã€? CompletionService cs = new ExecutorCompletionService(es); // æŒ‰æ–‡ä»¶å‘ CompletionService æäº¤ä»ÕdŠ¡ã€? for (final Path javaFile : javaFiles) { cs.submit(new Callable<Integer>() { @Override public Integer call() throws Exception { // 略去计算å•个文äšg行数的代ç ã€? return countLines(javaFile); } }); } try { int loc = 0; int size = javaFiles.size(); for (int i = 0; i < size; i++) { // take æ–ÒŽ³•½{‰å¾…ä¸‹ä¸€ä¸ªç»“æžœåÆˆ˜q”回 Future 对象。ä¸ç›´æŽ¥˜q”回计算¾l“æžœæ˜¯äØ“äº? // æ•获计算时å¯èƒ½æŠ›å‡ºçš„异常ã€? // poll ä¸ç‰å¾…,有结果就˜q”回一ä¸?Future 对象åQŒå¦åˆ™è¿”å›?nullã€? loc += cs.take().get(); } return loc; } finally { // 关闾U¿ç¨‹æ± 。也å¯ä»¥ž®†çº¿½E‹æ± æå‡ä¸ºå—ŒDµä»¥ä¾‰K‡ç”¨ã€? // 如果ä»ÕdŠ¡¾U¿ç¨‹åQˆCallable#callåQ‰èƒ½å“åº”ä¸æ–åQŒç”¨ shutdownNow 更好ã€? es.shutdown(); } }
最åŽï¼ŒCompletionService
ä¹Ÿä¸æ˜¯åˆ°å¤„都能用åQŒå®ƒä¸é€‚åˆå¤„ç†ä»ÕdŠ¡æ•°é‡æœ‰é™ä½†ä¸ªæ•îC¸å¯çŸ¥çš„场景。例如,è¦ç»Ÿè®¡æŸä¸ªæ–‡ä»¶å¤¹ä¸çš„æ–‡äšg个数åQŒåœ¨éåŽ†åæ–‡ä»¶å¤¹çš„æ—¶å€™ä¹Ÿä¼šâ€œé€’å½’åœ°â€æäº¤æ–°çš„ä“Q务,但最åŽåˆ°åº•æäº¤äº†å¤šå°‘åQŒä»¥åŠåœ¨ä»€ä¹ˆæ—¶å€™æäº¤å®Œäº†æ‰€æœ‰ä“Q务,都是未知敎ͼŒæ— 论 CompletionService
˜q˜æ˜¯¾U¿ç¨‹æ± éƒ½æ— æ³•˜q›è¡Œåˆ¤æ–。这¿U情况åªèƒ½ç›´æŽ¥ç”¨¾U¿ç¨‹æ± æ¥å¤„ç†ã€?/p>