一、執行緒池
a、固定大小的執行緒池
import java.util.concurrent.Executors; import java.util.concurrent.ExecutorService; /** * Java執行緒:執行緒池- * * */ public class Test { public static void main(String[] args) { //建立一個可重用固定執行緒數的執行緒池 ExecutorService pool = Executors.newFixedThreadPool(2); //建立實現了Runnable介面物件,Thread物件當然也實現了Runnable介面 Thread t1 = new MyThread(); Thread t2 = new MyThread(); Thread t3 = new MyThread(); Thread t4 = new MyThread(); Thread t5 = new MyThread(); //將執行緒放入池中進行執行 pool.execute(t1); pool.execute(t2); pool.execute(t3); pool.execute(t4); pool.execute(t5); //關閉執行緒池 pool.shutdown(); } } class MyThread extends Thread{ @Override public void run() { System.out.println(Thread.currentThread().getName()+"正在執行..."); } }
執行結果:
pool-1-thread-1正在執行... pool-1-thread-1正在執行... pool-1-thread-2正在執行... pool-1-thread-1正在執行... pool-1-thread-2正在執行...
如果將執行緒池的大小改為4,則執行結果如下:
pool-1-thread-2正在執行... pool-1-thread-3正在執行... pool-1-thread-3正在執行... pool-1-thread-2正在執行... pool-1-thread-1正在執行...
b、單任務執行緒池
在上例的基礎上改一行建立pool物件的程式碼為:
//建立一個使用單個 worker 執行緒的 Executor,以無界佇列方式來執行該執行緒。 ExecutorService pool = Executors.newSingleThreadExecutor();
則,執行結果為:
pool-1-thread-1正在執行... pool-1-thread-1正在執行... pool-1-thread-1正在執行... pool-1-thread-1正在執行... pool-1-thread-1正在執行...
c、可變尺寸的執行緒池
與上面的類似,只是改動下pool的建立方式:
//建立一個可根據需要建立新執行緒的執行緒池,但是在以前構造的執行緒可用時將重用它們。 ExecutorService pool = Executors.newCachedThreadPool();
執行結果如下:
pool-1-thread-1正在執行... pool-1-thread-5正在執行... pool-1-thread-4正在執行... pool-1-thread-3正在執行... pool-1-thread-2正在執行...
d、延遲連線池
package concurrent; import java.util.concurrent.Executors; import java.util.concurrent.ExecutorService; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; /** * Java執行緒:執行緒池- * * */ public class Test { public static void main(String[] args) { //建立一個執行緒池,它可那排在給定延遲後執行命令或者定期地執行 ScheduledExecutorService pool = Executors.newScheduledThreadPool(2); //建立實現了Runnable介面物件,Thread物件當然也實現了Runnable介面 Thread t1 = new MyThread(); Thread t2 = new MyThread(); Thread t3 = new MyThread(); Thread t4 = new MyThread(); Thread t5 = new MyThread(); //將執行緒放入池中進行執行 pool.execute(t1); pool.execute(t2); pool.execute(t3); //使用延遲執行風格的方法 pool.schedule(t4, 5, TimeUnit.SECONDS); pool.schedule(t5, 10, TimeUnit.SECONDS); //關閉執行緒池 pool.shutdown(); } } class MyThread extends Thread{ @Override public void run() { System.out.println(Thread.currentThread().getName()+"正在執行..."); } }
e、單任務連線執行緒池
在d的程式碼基礎上,做改動
//建立一個單執行緒執行程式,它可安排在給定延遲後執行命令或者定期地執行。 ScheduledExecutorService pool = Executors.newSingleThreadScheduledExecutor();
執行時,會發現,t4延遲5s後得到執行,t5延遲10s後得到執行。執行結果如下:
pool-1-thread-2正在執行... pool-1-thread-1正在執行... pool-1-thread-1正在執行... pool-1-thread-2正在執行... pool-1-thread-1正在執行...
f、自定義執行緒池
package concurrent; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; /** * Java執行緒:執行緒池-自定義執行緒池 * * */ public class Test { public static void main(String[] args) { //建立等待佇列 BlockingQueue<Runnable> bqueue = new ArrayBlockingQueue<Runnable>(20); //建立一個單執行緒執行程式,它可安排在給定延遲後執行命令或者定期地執行。 ThreadPoolExecutor pool = new ThreadPoolExecutor(2,3,2,TimeUnit.MILLISECONDS,bqueue); //建立實現了Runnable介面物件,Thread物件當然也實現了Runnable介面 Thread t1 = new MyThread(); Thread t2 = new MyThread(); Thread t3 = new MyThread(); Thread t4 = new MyThread(); Thread t5 = new MyThread(); Thread t6 = new MyThread(); Thread t7 = new MyThread(); //將執行緒放入池中進行執行 pool.execute(t1); pool.execute(t2); pool.execute(t3); pool.execute(t4); pool.execute(t5); pool.execute(t6); pool.execute(t7); //關閉執行緒池 pool.shutdown(); } } class MyThread extends Thread { @Override public void run() { System.out.println(Thread.currentThread().getName() + "正在執行..."); try { Thread.sleep(100L); } catch (InterruptedException e) { e.printStackTrace(); } } }
執行結構如下:
建立自定義執行緒池的構造方法很多,本例中引數的含義如下:
ThreadPoolExecutor
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue)
- 用給定的初始引數和預設的執行緒工廠及處理程式建立新的 ThreadPoolExecutor。使用
Executors
工廠方法之一比使用此通用構造方法方便得多。- 引數:
corePoolSize
- 池中所儲存的執行緒數,包括空閒執行緒。maximumPoolSize
- 池中允許的最大執行緒數。keepAliveTime
- 當執行緒數大於核心時,此為終止前多餘的空閒執行緒等待新任務的最長時間。unit
- keepAliveTime 引數的時間單位。workQueue
- 執行前用於保持任務的佇列。此佇列僅保持由 execute 方法提交的 Runnable 任務。- 丟擲:
IllegalArgumentException
- 如果 corePoolSize 或 keepAliveTime 小於零,或者 maximumPoolSize 小於或等於零,或者 corePoolSize 大於 maximumPoolSize。NullPointerException
- 如果 workQueue 為 null
二、有返回值的執行緒
下面是一個簡單的例子:
package MultiThread; import java.util.concurrent.*; /** * Java執行緒:有返回值的執行緒 * * */ public class Test { public static void main(String[] args) throws ExecutionException, InterruptedException { //建立一個執行緒池 ExecutorService pool = Executors.newFixedThreadPool(2); //建立兩個有返回值的任務 Callable<String> c1 = new MyCallable("A"); Callable<String> c2 = new MyCallable("B"); //執行任務並獲取Future物件 Future<String> f1 = pool.submit(c1); Future<String> f2 = pool.submit(c2); //從Future物件上獲取任務的返回值,並輸出到控制檯 System.out.println(">>>"+f1.get().toString()); System.out.println(">>>"+f2.get().toString()); //關閉執行緒池 pool.shutdown(); } } class MyCallable implements Callable<String>{ private String oid; MyCallable(String oid) { this.oid = oid; } @Override public String call() throws Exception { return oid+"任務返回的內容"; } }
執行結果:
>>>A任務返回的內容
>>>B任務返回的內容
比較簡單,要深入瞭解還需要看Callable和Future介面的API啊。
三、併發庫的鎖
在Java5中,專門提供了鎖物件,利用鎖可以方便的實現資源的封鎖,用來控制對競爭資源併發訪問的控制,這些內容主要集中在java.util.concurrent.locks 包下面,裡面有三個重要的介面Condition、Lock、ReadWriteLock。
介面摘要 | |
---|---|
Condition | Condition 將 Object 監視器方法(wait 、notify 和 notifyAll )分解成截然不同的物件,以便透過將這些物件與任意 Lock 實現組合使用,為每個物件提供多個等待 set(wait-set)。 |
Lock | Lock 實現提供了比使用 synchronized 方法和語句可獲得的更廣泛的鎖定操作。 |
ReadWriteLock | ReadWriteLock 維護了一對相關的鎖 ,一個用於只讀操作,另一個用於寫入操作。 |
有關鎖的介紹,API文件解說很多,看得很煩,還是看個例子再看文件比較容易理解
a、普通鎖
package MultiThread; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * Java執行緒:鎖 * * */ public class Test { public static void main(String[] args) { //建立併發訪問的賬戶 MyCount myCount = new MyCount("95599200901215522", 10000); //建立一個鎖物件 Lock lock = new ReentrantLock(); //建立一個執行緒池 ExecutorService pool = Executors.newCachedThreadPool(); //建立一些併發訪問使用者,一個信用卡,存的存,取的取,好熱鬧啊 UserThread ut1 = new UserThread("取款執行緒1", myCount, -4000, lock); UserThread ut2 = new UserThread("存款執行緒1", myCount, 6000, lock); UserThread ut3 = new UserThread("取款執行緒2", myCount, -8000, lock); UserThread ut4 = new UserThread("存款執行緒2", myCount, 800, lock); //線上程池中執行各個使用者的操作 pool.execute(ut1); pool.execute(ut2); pool.execute(ut3); pool.execute(ut4); //關閉執行緒池 pool.shutdown(); } } /** * 信用卡的使用者 執行緒 * 多個使用者執行緒操作該信用卡 */ class UserThread implements Runnable { private String threadName; //使用者執行緒 private MyCount myCount; //所要操作的賬戶 private int iocash; //操作的金額,當然有正負之分了 private Lock myLock; //執行操作所需的鎖物件 UserThread(String name, MyCount myCount, int iocash, Lock myLock) { this.threadName = name; this.myCount = myCount; this.iocash = iocash; this.myLock = myLock; } public void run() { //獲取鎖 myLock.lock(); //執行現金業務 System.out.println(threadName + "正在操作" + myCount + "賬戶,操作金額為" + iocash + ",當前金額為" + myCount.getCash()); myCount.setCash(myCount.getCash() + iocash); System.out.println("\t操作成功,操作金額為" + iocash + ",當前金額為" + myCount.getCash()); //釋放鎖,否則別的執行緒沒有機會執行了 myLock.unlock(); } } /** * 信用卡賬戶,可隨意透支 */ class MyCount { private String oid; //賬號 private int cash; //賬戶餘額 MyCount(String oid, int cash) { this.oid = oid; this.cash = cash; } public String getOid() { return oid; } public void setOid(String oid) { this.oid = oid; } public int getCash() { return cash; } public void setCash(int cash) { this.cash = cash; } @Override public String toString() { return "MyCount{" + "oid='" + oid + '\'' + ", cash=" + cash + '}'; } }
執行結果:
取款執行緒1正在操作MyCount{oid='95599200901215522', cash=10000}賬戶,操作金額為-4000,當前金額為10000 操作成功,操作金額為-4000,當前金額為6000 存款執行緒1正在操作MyCount{oid='95599200901215522', cash=6000}賬戶,操作金額為6000,當前金額為6000 操作成功,操作金額為6000,當前金額為12000 存款執行緒2正在操作MyCount{oid='95599200901215522', cash=12000}賬戶,操作金額為800,當前金額為12000 操作成功,操作金額為800,當前金額為12800 取款執行緒2正在操作MyCount{oid='95599200901215522', cash=12800}賬戶,操作金額為-8000,當前金額為12800 操作成功,操作金額為-8000,當前金額為4800
b、讀寫鎖
package MultiThread; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantReadWriteLock; /** * Java執行緒:鎖 * * */ public class Test { public static void main(String[] args) { //建立併發訪問的賬戶 MyCount myCount = new MyCount("95599200901215522", 10000); //建立一個鎖物件 ReadWriteLock lock = new ReentrantReadWriteLock(); //建立一個執行緒池 ExecutorService pool = Executors.newCachedThreadPool(); //建立一些併發訪問使用者執行緒,一個信用卡,存的存,取的取,好熱鬧啊 UserThread ut1 = new UserThread("取款執行緒1", myCount, -4000, lock,false); UserThread ut2 = new UserThread("存款執行緒1", myCount, 6000, lock,false); UserThread ut3 = new UserThread("取款執行緒2", myCount, -8000, lock,false); UserThread ut4 = new UserThread("存款執行緒2", myCount, 800, lock,false); UserThread ut5 = new UserThread("查詢", myCount, 0, lock,true); //線上程池中執行各個使用者的操作 pool.execute(ut1); pool.execute(ut2); pool.execute(ut3); pool.execute(ut4); pool.execute(ut5); //關閉執行緒池 pool.shutdown(); } } /** * 信用卡的使用者 執行緒 * 多個使用者執行緒操作該信用卡 */ class UserThread implements Runnable { private String threadName; //使用者執行緒 private MyCount myCount; //所要操作的賬戶 private int iocash; //操作的金額,當然有正負之分了 private ReadWriteLock myLock; //執行操作所需的鎖物件 private boolean ischeck; //是否查詢 UserThread(String name, MyCount myCount, int iocash, ReadWriteLock myLock,boolean ischeck) { this.threadName = name; this.myCount = myCount; this.iocash = iocash; this.myLock = myLock; this.ischeck=ischeck; } public void run() { if(ischeck){ //獲取讀鎖 myLock.readLock().lock(); //執行查詢 System.out.println("讀:"+threadName + "正在查詢" + myCount + "賬戶,,當前金額為" + myCount.getCash()); //釋放獲取到的讀鎖 myLock.readLock().unlock(); }else{ //獲取寫鎖 myLock.writeLock().lock(); myCount.setCash(myCount.getCash() + iocash); System.out.println("寫:"+threadName+"操作成功,操作金額為" + iocash + ",當前金額為" + myCount.getCash()); //釋放鎖獲取到的寫鎖 myLock.writeLock().unlock(); } } } /** * 信用卡賬戶,可隨意透支 */ class MyCount { private String oid; //賬號 private int cash; //賬戶餘額 MyCount(String oid, int cash) { this.oid = oid; this.cash = cash; } public String getOid() { return oid; } public void setOid(String oid) { this.oid = oid; } public int getCash() { return cash; } public void setCash(int cash) { this.cash = cash; } @Override public String toString() { return "MyCount{" + "oid='" + oid + '\'' + ", cash=" + cash + '}'; } }
執行結果:
寫:取款執行緒1操作成功,操作金額為-4000,當前金額為6000 寫:取款執行緒2操作成功,操作金額為-8000,當前金額為-2000 寫:存款執行緒1操作成功,操作金額為6000,當前金額為4000 讀:查詢正在查詢MyCount{oid='95599200901215522', cash=4000}賬戶,,當前金額為4000 寫:存款執行緒2操作成功,操作金額為800,當前金額為4800
在實際開發中,最好在能用讀寫鎖的情況下使用讀寫鎖,而不要用普通鎖,以求更好的效能。
四、訊號量
下面是一個簡單的例子:
package MultiThread; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Semaphore; /** * Java執行緒:訊號量 * * */ public class Test { public static void main(String[] args) { MyPool myPool = new MyPool(20); //建立執行緒池 ExecutorService threadPool = Executors.newFixedThreadPool(2); MyThread t1 = new MyThread("任務A", myPool, 3); MyThread t2 = new MyThread("任務B", myPool, 12); MyThread t3 = new MyThread("任務C", myPool, 7); //線上程池中執行任務 threadPool.execute(t1); threadPool.execute(t2); threadPool.execute(t3); //關閉池 threadPool.shutdown(); } } /** * 一個池 */ class MyPool { private Semaphore sp; //池相關的訊號量 /** * 池的大小,這個大小會傳遞給訊號量 * * @param size 池的大小 */ MyPool(int size) { this.sp = new Semaphore(size); } public Semaphore getSp() { return sp; } public void setSp(Semaphore sp) { this.sp = sp; } } class MyThread extends Thread { private String threadName; //執行緒的名稱 private MyPool pool; //自定義池 private int x; //申請訊號量的大小 MyThread(String threadName, MyPool pool, int x) { this.threadName = threadName; this.pool = pool; this.x = x; } public void run() { try { //從此訊號量獲取給定數目的許可 pool.getSp().acquire(x); //todo:也許這裡可以做更復雜的業務 System.out.println(threadName + "成功獲取了" + x + "個許可!"); } catch (InterruptedException e) { e.printStackTrace(); } finally { //釋放給定數目的許可,將其返回到訊號量。 pool.getSp().release(x); System.out.println(threadName + "釋放了" + x + "個許可!"); } } }
執行結果:
任務A成功獲取了3個許可!
任務B成功獲取了12個許可!
任務B釋放了12個許可!
任務C成功獲取了7個許可!
任務A釋放了3個許可!
任務C釋放了7個許可!
從結果可以看出,訊號量僅僅是對池資源進行監控,但不保證執行緒的安全,因此,在使用時候,應該自己控制執行緒的安全訪問池資源。
五、阻塞佇列
package MultiThread; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ArrayBlockingQueue; /** * Java執行緒:併發庫-阻塞佇列 * * */ public class Test { public static void main(String[] args) throws InterruptedException { BlockingQueue<Integer> bqueue = new ArrayBlockingQueue<Integer>(20); for (int i = 0; i < 30; i++) { //將指定元素新增到此佇列中,如果沒有可用空間,將一直等待(如果有必要)。 bqueue.put(i); System.out.println("向阻塞佇列中新增了元素:" + i); } System.out.println("程式到此執行結束,即將退出----"); } }
執行結果:
六、阻塞棧
package MultiThread; import java.util.concurrent.BlockingDeque; import java.util.concurrent.LinkedBlockingDeque; class HelloWorldThread { /** * Java執行緒:併發庫-阻塞棧 * * */ public static void main(String[] args) { BlockingDeque<Integer> bstack=new LinkedBlockingDeque<Integer>(20) ; for(int i=0;i<30;i++){ //將指定元素新增到阻塞棧中,如果沒有可用空間,將一直等待(如果有必要)。 bstack.push(i); System.out.println("向阻塞棧中新增了元素:" + i); if(bstack.size()==20){ System.out.println("佇列滿,彈出"+bstack.pop()); System.out.println("佇列滿,彈出"+bstack.pop()); System.out.println("佇列滿,彈出"+bstack.pop()); } } System.out.println("程式到此執行結束,即將退出----"); } }
程式的執行結果和阻塞佇列的執行結果一樣,程式並沒結束,二是阻塞住了,原因是棧已經滿了,後面追加元素的操作都被阻塞了。
七、條件變數
package MultiThread; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * Java執行緒:條件變數 * * @author leizhimin 2009-11-5 10:57:29 */ public class Test { public static void main(String[] args) { //建立併發訪問的賬戶 MyCount myCount = new MyCount("95599200901215522", 10000); //建立一個執行緒池 ExecutorService pool = Executors.newFixedThreadPool(2); Thread t1 = new SaveThread("張三", myCount, 2000); Thread t2 = new SaveThread("李四", myCount, 3600); Thread t3 = new DrawThread("王五", myCount, 2700); Thread t4 = new SaveThread("老張", myCount, 600); Thread t5 = new DrawThread("老牛", myCount, 1300); Thread t6 = new DrawThread("胖子", myCount, 800); //執行各個執行緒 pool.execute(t1); pool.execute(t2); pool.execute(t3); pool.execute(t4); pool.execute(t5); pool.execute(t6); //關閉執行緒池 pool.shutdown(); } } /** * 存款執行緒類 */ class SaveThread extends Thread { private String name; //操作人 private MyCount myCount; //賬戶 private int x; //存款金額 SaveThread(String name, MyCount myCount, int x) { this.name = name; this.myCount = myCount; this.x = x; } public void run() { myCount.saving(x, name); } } /** * 取款執行緒類 */ class DrawThread extends Thread { private String name; //操作人 private MyCount myCount; //賬戶 private int x; //存款金額 DrawThread(String name, MyCount myCount, int x) { this.name = name; this.myCount = myCount; this.x = x; } public void run() { myCount.drawing(x, name); } } /** * 普通銀行賬戶,不可透支 */ class MyCount { private String oid; //賬號 private int cash; //賬戶餘額 private Lock lock = new ReentrantLock(); //賬戶鎖 private Condition _save = lock.newCondition(); //存款條件 private Condition _draw = lock.newCondition(); //取款條件 MyCount(String oid, int cash) { this.oid = oid; this.cash = cash; } /** * 存款 * * @param x 操作金額 * @param name 操作人 */ public void saving(int x, String name) { lock.lock(); //獲取鎖 if (x > 0) { cash += x; //存款 System.out.println(name + "存款" + x + ",當前餘額為" + cash); } _draw.signalAll(); //喚醒所有取款等待執行緒 lock.unlock(); //釋放鎖 } /** * 取款 * * @param x 操作金額 * @param name 操作人 */ public void drawing(int x, String name) { lock.lock(); //獲取鎖 try { if (cash - x < 0) { _draw.await(); //阻塞取款操作 } else { cash -= x; //取款 System.out.println(name + "取款" + x + ",當前餘額為" + cash); } _save.signalAll(); //喚醒所有存款操作執行緒 } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); //釋放鎖 } } }
當然,除了使用併發庫來實現存取款操作,我們也可以使用synchronized的方法、synchronized的程式碼塊來實現。對比並發庫、synchronized方法、synchronized程式碼塊,第一種最靈活,第二種程式碼最簡單,第三種容易犯錯。
八、原子量
package MultiThread; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicLong; /** * Java執行緒:新特徵-原子量 * * */ public class Test { public static void main(String[] args) { ExecutorService pool = Executors.newFixedThreadPool(2); Runnable t1 = new MyRunnable("張三", 2000); Runnable t2 = new MyRunnable("李四", 3600); Runnable t3 = new MyRunnable("王五", 2700); Runnable t4 = new MyRunnable("老張", 600); Runnable t5 = new MyRunnable("老牛", 1300); Runnable t6 = new MyRunnable("胖子", 800); //執行各個執行緒 pool.execute(t1); pool.execute(t2); pool.execute(t3); pool.execute(t4); pool.execute(t5); pool.execute(t6); //關閉執行緒池 pool.shutdown(); } } class MyRunnable implements Runnable { private static AtomicLong aLong = new AtomicLong(10000); //原子量,每個執行緒都可以自由操作 private String name; //操作人 private int x; //運算元額 MyRunnable(String name, int x) { this.name = name; this.x = x; } public void run() { System.out.println(name + "執行了" + x + ",當前餘額:" + aLong.addAndGet(x)); } }
執行結果一:
李四執行了3600,當前餘額:13600 張三執行了2000,當前餘額:15600 老張執行了600,當前餘額:18900 老牛執行了1300,當前餘額:20200 胖子執行了800,當前餘額:21000 王五執行了2700,當前餘額:18300
執行結果二:
張三執行了2000,當前餘額:12000 王五執行了2700,當前餘額:14700 老張執行了600,當前餘額:15300 老牛執行了1300,當前餘額:16600 胖子執行了800,當前餘額:17400 李四執行了3600,當前餘額:21000
執行結果三:
張三執行了2000,當前餘額:12000 王五執行了2700,當前餘額:18300 老張執行了600,當前餘額:18900 老牛執行了1300,當前餘額:20200 胖子執行了800,當前餘額:21000 李四執行了3600,當前餘額:15600
package MultiThread; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * Java執行緒:併發庫-原子量 * * */ public class Test { public static void main(String[] args) { ExecutorService pool = Executors.newFixedThreadPool(2); Lock lock=new ReentrantLock(); Runnable t1 = new MyRunnable("張三", 2000,lock); Runnable t2 = new MyRunnable("李四", 3600,lock); Runnable t3 = new MyRunnable("王五", 2700,lock); Runnable t4 = new MyRunnable("老張", 600,lock); Runnable t5 = new MyRunnable("老牛", 1300,lock); Runnable t6 = new MyRunnable("胖子", 800,lock); //執行各個執行緒 pool.execute(t1); pool.execute(t2); pool.execute(t3); pool.execute(t4); pool.execute(t5); pool.execute(t6); //關閉執行緒池 pool.shutdown(); } } class MyRunnable implements Runnable { private static AtomicLong aLong = new AtomicLong(10000); //原子量,每個執行緒都可以自由操作 private String name; //操作人 private int x; //運算元額 private Lock lock; MyRunnable(String name, int x,Lock lock) { this.name = name; this.x = x; this.lock=lock; } public void run() { lock.lock(); System.out.println(name + "執行了" + x + ",當前餘額:" + aLong.addAndGet(x)); lock.unlock(); } }
執行結果:
張三執行了2000,當前餘額:12000 李四執行了3600,當前餘額:15600 王五執行了2700,當前餘額:18300 老張執行了600,當前餘額:18900 老牛執行了1300,當前餘額:20200 胖子執行了800,當前餘額:21000
九、障礙器
Java5中,新增了障礙器類,為了適應一種新的設計需求,比如一個大型的任務,常常需要分配好多子任務去執行,只有當所有子任務都執行完成時候,才能執行主任務,這時候,就可以選擇障礙器了。障礙器是多執行緒併發控制的一種手段,用法很簡單。
下面給個例子:
package MultiThread; import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.CyclicBarrier; /** * Java執行緒:新特徵-障礙器 * * */ public class Test { public static void main(String[] args) { //建立障礙器,並設定MainTask為所有定數量的執行緒都達到障礙點時候所要執行的任務(Runnable) CyclicBarrier cb = new CyclicBarrier(7, new MainTask()); new SubTask("A", cb).start(); new SubTask("B", cb).start(); new SubTask("C", cb).start(); new SubTask("D", cb).start(); new SubTask("E", cb).start(); new SubTask("F", cb).start(); new SubTask("G", cb).start(); } } /** * 主任務 */ class MainTask implements Runnable { public void run() { System.out.println(">>>>主任務執行了!<<<<"); } } /** * 子任務 */ class SubTask extends Thread { private String name; private CyclicBarrier cb; SubTask(String name, CyclicBarrier cb) { this.name = name; this.cb = cb; } public void run() { System.out.println("[子任務" + name + "]開始執行了!"); for (int i = 0; i < 999999; i++) ; //模擬耗時的任務 System.out.println("[子任務" + name + "]開始執行完成了,並通知障礙器已經完成!"); try { //通知障礙器已經完成,讓出鎖(並使得,跳躍的障礙數目-1) cb.await(); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } } }
執行結果:
[子任務B]開始執行了!
[子任務E]開始執行了!
[子任務C]開始執行了!
[子任務D]開始執行了!
[子任務A]開始執行了!
[子任務E]開始執行完成了,並通知障礙器已經完成!
[子任務B]開始執行完成了,並通知障礙器已經完成!
[子任務A]開始執行完成了,並通知障礙器已經完成!
[子任務C]開始執行完成了,並通知障礙器已經完成!
[子任務D]開始執行完成了,並通知障礙器已經完成!
[子任務F]開始執行了!
[子任務F]開始執行完成了,並通知障礙器已經完成!
[子任務G]開始執行了!
[子任務G]開始執行完成了,並通知障礙器已經完成!
>>>>主任務執行了!<<<<
從執行結果可以看出,所有子任務完成的時候,主任務執行了,達到了控制的目標