1. 建立和啟動線程的兩種傳統方式
概念:java 實現一條線索
有兩種方法:
1、繼承thread 類
例子:
// 繼承Thread類
new Thread(){ publicvoid run(){ while(true){ try { Thread.sleep(2000); }catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()); } } }.start();
2、實現runnable介面
例子:
//實現Runnable介面 new Thread(new Runnable(){ publicvoid run(){ while(true){ try { Thread.sleep(2000); }catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()); } } }).start();
2.傳統的定時器實現方式
代碼
importjava.util.concurrent.Executors;importjava.util.concurrent.ScheduledExecutorService;import java.util.concurrent.TimeUnit;publicclass TimerTest { /** * 定時器 */ publicstaticvoid main(String[] args) { ScheduledExecutorServiceservice = Executors.newScheduledThreadPool(3); service.scheduleAtFixedRate( new Runnable(){ publicvoid run() { System.out.println(Thread.currentThread().getName()); } }, 10, 1, TimeUnit.SECONDS); while(true){ try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()); } }}
3.傳統的線程同步互斥
線程的同步和互斥 Synchronized線程建立過程:同步:子線程迴圈10次,接著主線程迴圈100次,接著的又回到子線程迴圈10次,接著又回到主線程迴圈10次。如此,迴圈50次。
packageorg.nagi.Thread;publicclass TeaTSynchronized { static Businessbusiness =new Business(); publicstaticvoid main(String[] args)throws InterruptedException { //子線程 TeaTSynchronized.init(); //主線程 for(int i=0;i<50;i++){ business.main(); } } //子線程 publicstaticvoid init(){ new Thread(new Runnable() { @Override publicvoid run() { for(int i=0;i<50;i++){ try { business.sub(); }catch (InterruptedException e) { e.printStackTrace(); } } } }).start(); }}
class Business{ booleanshouldSub =true; //子線程方法 publicsynchronizedvoid sub()throws InterruptedException{ //使用我當前線程的,等待 while(!shouldSub){//這裡使用while而不用iF防止假喚醒。詳細資料可參考JavaApi this.wait(); } for(int i=0;i<10;i++){ System.out.println(Thread.currentThread().getName()+"count" + i); } shouldSub = false; this.notify(); } //主線程的操作方法 publicsynchronizedvoid main()throws InterruptedException{ while(shouldSub){//這裡使用while而不用iF防止假喚醒。詳細資料可參考JavaApi //使用我當前線程的,等待 this.wait(); } for(int i=0;i<100;i++){ System.out.println(Thread.currentThread().getName()+"count" + i); } shouldSub = true; this.notify(); }}
4.傳統的線程間通訊
ThreadLoacal 線程間的通訊:就是線程內的資料共用,兩個或多個代碼塊共用的一個資料, 在代碼塊之間資料是獨立,在代碼塊之內是資料共用的。
5.ThreadLocal與線程級變數共用
ThreadLoacal就相當Map; 一個線程TheadLoacal 只能放一個資料;
6.多線程訪問共用資料的經典總結
1、可以把需要共用的資料轉給runnable 介面; 2、將共用資料的封裝為一個對象, 在多個線程裡面runnable 介面run方法 3、可以使用ThreadLocal類
如果想要操作一個原子性的資料類型可以用原子方式更新的 int 值。
在操作某一個資料原子性操作的時候,可以使用AtomicInteger AtomicIntegerArray
定義一個線程池:
packageorg.nagi.Thread;importjava.util.concurrent.ExecutorService;importjava.util.concurrent.Executors;/** *線程池 *@author dell * */publicclass ThreadPool { publicstaticvoid main(String[] args) { /*緩衝線程池*/ //ExecutorService threadcached=Executors.newCachedThreadPool(); /*單個線程池,當線程死了,自動會有線程啟動*/ //ExecutorService threadSingle = Executors.newSingleThreadScheduledExecutor(); //線程池 ExecutorService threadPool = Executors.newFixedThreadPool(4); threadPool.execute(new Runnable() { @Override publicvoid run() { for(int i=0;i<5;i++){ System.out.println(Thread.currentThread().getName()+"任務:"+ i); } } }); //當任務執行完成之後就可以關閉掉 threadPool.shutdown(); }}
8.Java5中的定時器
方法參考
ScheduledFuture
schedule(Callable callable, long delay, TimeUnit unit)
建立並執行在給定延遲後啟用的 ScheduledFuture。
ScheduledFuture
Executors.newScheduledThreadPool(4).scheduleAtFixedRate( new Runnable() { @Override publicvoid run() { System.out.println("Bombing"); } }, 4,//多少秒之後執行run方法 2,//間隔多少時間執行 TimeUnit.SECONDS);//時間單位Callable和Futrue使用: /*使用Callable調用回返一個資料,使用futrue去取並且可以指定時間*/ ExecutorService threadSingle = Executors.newSingleThreadExecutor(); Future<String> futrue =threadSingle.submit(newCallable<String>() { @Override public String call()throws Exception { Thread.sleep(1000); return"hello world"; } }); try { //futrue取出資料 System.out.println("result:" + futrue.get(3,TimeUnit.SECONDS)); } catch (Exceptione) { e.printStackTrace(); }
9.java5提供的可返回結果的線程模式
10.java5中的鎖與讀寫鎖
Lock:java 中鎖Lock 比Synchronized更加的面對對象,與生活中的對象一樣,鎖業是一個對象。
例子代碼:
importjava.util.concurrent.ExecutorService;importjava.util.concurrent.Executors;importjava.util.concurrent.locks.Lock;importjava.util.concurrent.locks.ReentrantLock;publicclass LockTest { /** * @param args */ publicstaticvoid main(String[] args) { final Business business =new Business(); ExecutorService service = Executors.newFixedThreadPool(3); for(int i=0;i<3;i++){ service.execute(new Runnable(){ publicvoid run(){ business.service(); } }); } service.shutdown(); }}class Business{ privateintcount = 0; Lock lock = new ReentrantLock(); publicvoid service(){ lock.lock(); count++; try { Thread.sleep(10); System.out.println(count); } catch (InterruptedException e) { e.printStackTrace(); }finally{ lock.unlock(); } }}Lock : 還可以實現一個讀寫鎖,/** * 讀的的時候不互斥 * 寫的時候互斥 * @param key * @return */ public Object getEntityFromCache(Stringkey){ Object object = cache.get(key); if(object ==null){ lock.readLock().lock();//鎖得read操作 try{ object ="btbu";//去資料庫尋找 cache.put(key, object); }finally{ lock.readLock().unlock(); } } return object; }
11.LockCondition同步工具
Condition 將 Object 監視器方法(wait、notify和notifyAll)分解成截然不同的對象,以便通過將這些對象與任意Lock 實現組合使用,為每個對象提供多個等待 set(wait-set)。其中,Lock 替代了 synchronized 方法和語句的使用,Condition 替代了 Object 監視器方法的使用。
例子:
packageorg.nagi.Thread;import java.util.concurrent.locks.Condition;importjava.util.concurrent.locks.ReentrantLock;publicclass TestCondition { static Businessbusiness =new Business(); publicstaticvoid main(String[] args)throws InterruptedException { //子線程 TestCondition.init(); //主線程 for(int i=0;i<50;i++){ business.main(); } } //子線程 publicstaticvoid init(){ new Thread(new Runnable() { @Override publicvoid run() { for(int i=0;i<50;i++){ try { business.sub(); }catch (InterruptedException e) { e.printStackTrace(); } } } }).start(); }}
class Business{ booleanshouldSub =true; ReentrantLock lock = new ReentrantLock(); Condition condition =lock.newCondition(); //子線程方法 public void sub()throws InterruptedException{ lock.lock(); try{ //使用我當前線程的,等待 while(!shouldSub){//這裡使用while而不用iF防止假喚醒。詳細資料可參考JavaApi condition.await(); } for(int i=0;i<10;i++){ System.out.println(Thread.currentThread().getName()+"count" + i); } shouldSub =false; }finally{ condition.signal(); } } //主線程的操作方法 publicsynchronizedvoid main()throws InterruptedException{ lock.lock(); try{ while(shouldSub){//這裡使用while而不用iF防止假喚醒。詳細資料可參考JavaApi //使用我當前線程的,等待 condition.await(); } for(int i=0;i<100;i++){ System.out.println(Thread.currentThread().getName()+"count" + i); } shouldSub = true; this.notify(); }finally{ condition.signal(); } }}
緩衝隊列的實現
import java.util.concurrent.locks.Condition;importjava.util.concurrent.locks.Lock;importjava.util.concurrent.locks.ReentrantLock;/** *緩衝隊列 *@author dell * */class BoundedBuffer{ final Locklock =new ReentrantLock(); final ConditionnotFull =lock.newCondition(); final ConditionnotEmpty =lock.newCondition(); //一個數組的緩衝區 final Object[]items =new Object[100]; intputptr,takeptr,count; //存放的操作 publicvoid put(Object x)throws InterruptedException { lock.lock(); try { while (count ==items.length) notFull.await(); items[putptr] = x; if (++putptr ==items.length)putptr = 0; ++count; notEmpty.signal(); } finally { lock.unlock(); } } //取出資料的操作 public Object take()throwsInterruptedException { lock.lock(); try { while (count == 0) notEmpty.await(); Object x = items[takeptr]; if (++takeptr ==items.length)takeptr = 0; --count; notFull.signal(); return x; } finally { lock.unlock(); } } }
12.Semaphore同步工具
代碼:
importjava.util.concurrent.ExecutorService;importjava.util.concurrent.Executors;importjava.util.concurrent.Semaphore;/** *號誌 *@author dell * */publicclass SemaphoreTest { publicstaticvoid main(String[] args) { //緩衝串連池 ExecutorService service = Executors.newCachedThreadPool(); final Semaphore sp =new Semaphore(3); for(int i=0;i<10;i++){ Runnable runnable = new Runnable(){ publicvoid run(){ try { sp.acquire();//獲得訊號量許可 }catch (InterruptedException e1) { e1.printStackTrace(); } System.out.println("線程" + Thread.currentThread().getName() + "進入,當前已有" + (3-sp.availablePermits()) +"個並發"); try { Thread.sleep((long)(Math.random()*10000)); }catch (InterruptedException e) { e.printStackTrace(); } System.out.println("線程" + Thread.currentThread().getName() + "即將離開"); sp.release();//釋放訊號量 //下面代碼有時候執行不準確,因為其沒有和上面的代碼合成原子單元 System.out.println("線程" + Thread.currentThread().getName() + "已離開,當前已有" + (3-sp.availablePermits()) +"個並發"); } }; //執行已提交的 Runnable任務的對象。 service.execute(runnable); } }}
運行結果:
線程pool-1-thread-1進入,當前已有1個並發
線程pool-1-thread-1即將離開
線程pool-1-thread-1已離開,當前已有0個並發
線程pool-1-thread-2進入,當前已有1個並發
線程pool-1-thread-2即將離開
線程pool-1-thread-2已離開,當前已有0個並發
線程pool-1-thread-3進入,當前已有1個並發
線程pool-1-thread-3即將離開
13.CyclicBarrier同步工具
一個同步輔助類,它允許一組線程互相等待,直到到達某個公用屏障點 (common barrier point)。在涉及一組固定大小的線程的程式中,這些線程必須不時地互相等待,此時 CyclicBarrier 很有用。因為該 barrier 在釋放等待線程後可以重用,所以稱它為迴圈的 barrier。
代碼:
import java.util.concurrent.CyclicBarrier;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;/** *並發工具輔佐類 * *之迴圈障礙點 *@author dell * */publicclass CyclicBarrierTest { publicstaticvoid main(String[] args) { ExecutorService service = Executors.newCachedThreadPool(); final CyclicBarrier cb =newCyclicBarrier(3); for(int i=0;i<3;i++){ Runnable runnable = new Runnable(){ publicvoid run(){ try { Thread.sleep((long)(Math.random()*10000)); System.out.println("線程" + Thread.currentThread().getName() + "即將到達集合地點1,當前已有" + cb.getNumberWaiting() +"個已經到達,正在等候"); cb.await(); Thread.sleep((long)(Math.random()*10000)); System.out.println("線程" + Thread.currentThread().getName() + "即將到達集合地點2,當前已有" + cb.getNumberWaiting() +"個已經到達,正在等候"); cb.await(); Thread.sleep((long)(Math.random()*10000)); System.out.println("線程" + Thread.currentThread().getName() + "即將到達集合地點3,當前已有" + cb.getNumberWaiting() +"個已經到達,正在等候"); cb.await(); }catch (Exception e) { e.printStackTrace(); } } }; service.execute(runnable); } service.shutdown(); }}
14.CountDownLatch同步工具
一個同步輔助類,在完成一組正在其他線程中執行的操作之前,它允許一個或多個線程一直等待。首先先是點時器,
用給定的計數 初始化 CountDownLatch。由於調用了countDown()方法,所以在當前計數到達零之前,await方法會一直受阻塞。之後,會釋放所有等待的線程,await的所有後續調用都將立即返回。這種現象只出現一次——計數無法被重設。
importjava.util.concurrent.CountDownLatch;importjava.util.concurrent.ExecutorService;importjava.util.concurrent.Executors;/** *程式計數器 *@author dell * */publicclass CountdownLatchTest { publicstaticvoid main(String[] args) { ExecutorService service = Executors.newCachedThreadPool(); //命令 final CountDownLatch cdOrder =new CountDownLatch(1); //需要3個都為了時候再執行 final CountDownLatch cdAnswer =new CountDownLatch(3); for(int i=0;i<3;i++){ Runnable runnable = new Runnable(){ publicvoid run(){ try { System.out.println("線程" + Thread.currentThread().getName() + "正準備接受命令"); cdOrder.await(); System.out.println("線程" + Thread.currentThread().getName() + "已接受命令"); Thread.sleep((long)(Math.random()*10000)); System.out.println("線程" + Thread.currentThread().getName() + "回應命令處理結果"); //減1,當計數器為0的時候,再可以往下執行 cdAnswer.countDown(); }catch (Exception