先說說Semaphore,Semaphore能夠控制某個資源可被同時訪問的個數,經過 acquire() 獲取一個許可,若是沒有就等待,而 release() 釋放一個許可。通常用於
控制併發線程數,及線程間互斥
。另外重入鎖 ReentrantLock 也能夠實現該功能,但實現上要複雜些。
功能就相似廁全部5個坑,假若有10我的要上廁所,那麼同時只能有多少我的去上廁所呢?同時只能有5我的可以佔用,當5我的中 的任何一我的讓開後,其中等待的另外5我的中又有一我的能夠佔用了。另外等待的5我的中能夠是隨機得到優先機會,也能夠是按照先來後到的順序得到機會。
單個信號量的Semaphore對象能夠實現互斥鎖的功能,而且能夠是由一個線程得到了「鎖」,再由另外一個線程釋放「鎖」,這可應用於死鎖恢復的一些場合。java
/** * @Description: * @param @param args * @return void 返回類型 */ public static void main(String[] args) { // 線程池 ExecutorService exec = Executors.newCachedThreadPool(); // 只能5個線程同時訪問 final Semaphore semp = new Semaphore(5); // 模擬20個客戶端訪問 for (int index = 0; index < 20; index++) { final int NO = index; Runnable run = new Runnable() { public void run() { try { // 獲取許可 semp.acquire(); System.out.println("得到Accessing: " + NO); Thread.sleep((long) (Math.random() * 10000)); // 訪問完後,釋放 semp.release(); System.out.println("剩餘可用信號-----------------" + semp.availablePermits()); } catch (InterruptedException e) { e.printStackTrace(); } } }; exec.execute(run); } // 退出線程池 exec.shutdown(); }
得到Accessing: 1 得到Accessing: 5 得到Accessing: 2 得到Accessing: 3 得到Accessing: 0 剩餘可用信號-----------------1 得到Accessing: 4 剩餘可用信號-----------------1 得到Accessing: 9 剩餘可用信號-----------------1 得到Accessing: 8 剩餘可用信號-----------------1 得到Accessing: 6 剩餘可用信號-----------------1 得到Accessing: 10 剩餘可用信號-----------------1 得到Accessing: 11 剩餘可用信號-----------------1 得到Accessing: 12 剩餘可用信號-----------------1 得到Accessing: 13 剩餘可用信號-----------------1 得到Accessing: 7 剩餘可用信號-----------------1 得到Accessing: 15 剩餘可用信號-----------------1 得到Accessing: 16 剩餘可用信號-----------------1 得到Accessing: 17 剩餘可用信號-----------------1 得到Accessing: 14 剩餘可用信號-----------------1 得到Accessing: 18 剩餘可用信號-----------------1 得到Accessing: 19 剩餘可用信號-----------------1 剩餘可用信號-----------------2 剩餘可用信號-----------------3 剩餘可用信號-----------------4 剩餘可用信號-----------------5
Pipe有一個source通道和一個sink通道。數據會被寫到sink通道,從source通道讀取。一進一出。先做爲初步瞭解怎麼使用。
值得注意的是該類在java.nio.channels下,說明該類屬於nio方式的數據通訊方式,那就使用Buffer來緩衝數據。併發
Pipe原理的圖示: app
操做流程:dom
寫的時候就是寫到管子自己包含的這段空間裏的。這段空間大小是1024個字節。函數
package com.jx.test; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.Pipe; public class testPipe { /** * @Description: * @param @param args * @return void 返回類型 * @throws IOException */ public static void main(String[] args) throws IOException { // 建立一個管道 Pipe pipe = Pipe.open(); final Pipe.SinkChannel psic = pipe.sink();// 要向管道寫數據,須要訪問sink通道 final Pipe.SourceChannel psoc = pipe.source();// 從讀取管道的數據,須要訪問source通道 Thread tPwriter = new Thread() { public void run() { try { System.out.println("send....."); // 建立一個線程,利用管道的寫入口Pipe.SinkChannel類型的psic往管道里寫入指定ByteBuffer的內容 int res = psic.write(ByteBuffer .wrap("Hello,Pipe!測試通信.....".getBytes("utf-16BE"))); System.out.println("send size:" + res); } catch (Exception e) { e.printStackTrace(); } } }; Thread tPreader = new Thread() { public void run() { int bbufferSize = 1024 * 2; ByteBuffer bbuffer = ByteBuffer.allocate(bbufferSize); try { System.out.println("recive....."); // 建立一個線程,利用管道的讀入口Pipe.SourceChannel類型的psoc將管道里內容讀到指定的ByteBuffer中 int res = psoc.read(bbuffer);//數據未 System.out.println("recive size:"+res+" Content:" + ByteBufferToString(bbuffer)); } catch (Exception e) { e.printStackTrace(); } } }; tPwriter.start(); tPreader.start(); } /** *ByteBuffer--> String的轉換函數 */ public static String ByteBufferToString(ByteBuffer content) { if (content == null || content.limit() <= 0 || (content.limit() == content.remaining())) { System.out.println("不存在或內容爲空!"); return null; } int contentSize = content.limit() - content.remaining(); StringBuffer resultStr = new StringBuffer(); for (int i = 0; i < contentSize; i += 2) { resultStr.append(content.getChar(i)); } return resultStr.toString(); } }