java多线程一览
- 線程概述:
- 多線程的目的,不是提高程序的執行速度,而是提高程序的使用率(能搶到CPU的可能比較大). 因為線程是CPU調度的基本單位,所以,當一個程序的線程較多的時候就更容易搶到cpu的資源
- 進程:
- 運行中的程序,是系統進行資源分配和調度的獨立單位
- 每個進程都有他自己的內存空間和系統資源
- 線程:
- 是進程中的單個順序控制流,是一條執行路徑,是cpu調度的基本單位
- 一個進程如果有多條執行路徑,稱:多線程
- 一個進程如果只有一條執行路徑,稱:單線程
- 線程生命周期:
-
?
-
- java中線程概覽: [ ps : 圖來自郭朝:http://blog.csdn.net/smartbetter/article/details/51335165]
- 繼承Thread類 和 實現Runnable:
- 實現Runnable創建線程類:
1 // 實現Runnable創建線程類 2 class MyRunnable implements Runnable{ 3 private Object shareData; // 實現數據共享 4 public void run(){ 5 System.out.println("當前線程是"+Thread.currentThread.getName()); 6 } 7 } 8 //創建線程 9 class Main{ 10 public static void main(String[] args) { 11 // 兩個線程將共享shareData共享數據 12 Runnable runa=new MyRunnable(); 13 Thread thread=new MyThread(runa); 14 Thread thread2=new MyThread(runa); 15 thread.start(); // 線程開啟 16 thread2.start(); // 線程開啟 17 } 18 } View Code
- 使用Callable 和 Future接口:
1 /** 2 * 該代碼來源: @蠱惑Into 3 * Callable 和 Future接口 4 * Callable是類似于Runnable的接口,實現Callable接口的類和實現Runnable的類都是可被其它線程執行的任務。 5 * Callable和Runnable有幾點不同: 6 * (1)Callable規定的方法是call(),而Runnable規定的方法是run(). 7 * (2)Callable的任務執行后可返回值,而Runnable的任務是不能返回值的。 8 * (3)call()方法可拋出異常,而run()方法是不能拋出異常的。 9 * (4)運行Callable任務可拿到一個Future對象, 10 * Future 表示異步計算的結果。它提供了檢查計算是否完成的方法,以等待計算的完成,并檢索計算的結果。 11 * 通過Future對象可了解任務執行情況,可取消任務的執行,還可獲取任務執行的結果。 12 */ 13 public class CallableAndFuture { 14 15 public static class MyCallable implements Callable{ 16 private int flag = 0; 17 public MyCallable(int flag){ 18 this.flag = flag; 19 } 20 public String call() throws Exception{ 21 if (this.flag == 0){ 22 return "flag = 0"; 23 } 24 if (this.flag == 1){ 25 try { 26 while (true) { 27 System.out.println("looping."); 28 Thread.sleep(2000); 29 } 30 } catch (InterruptedException e) { 31 System.out.println("Interrupted"); 32 } 33 return "false"; 34 } else { 35 throw new Exception("Bad flag value!"); 36 } 37 } 38 } 39 40 public static void main(String[] args) { 41 42 // 定義3個Callable類型的任務 43 MyCallable task1 = new MyCallable(0); 44 MyCallable task2 = new MyCallable(1); 45 MyCallable task3 = new MyCallable(2); 46 47 // 創建一個執行任務的服務 48 ExecutorService es = Executors.newFixedThreadPool(3); 49 try { 50 // 提交并執行任務,任務啟動時返回了一個Future對象, 51 52 // 如果想得到任務執行的結果或者是異常可對這個Future對象進行操作 53 Future future1 = es.submit(task1); 54 // 獲得第一個任務的結果,如果調用get方法,當前線程會等待任務執行完畢后才往下執行 55 System.out.println("task1: " + future1.get()); 56 57 58 Future future2 = es.submit(task2); 59 // 等待5秒后,再停止第二個任務。因為第二個任務進行的是無限循環 60 Thread.sleep(5000); 61 System.out.println("task2 cancel: " + future2.cancel(true)); 62 63 64 // 獲取第三個任務的輸出,因為執行第三個任務會引起異常 65 // 所以下面的語句將引起異常的拋出 66 Future future3 = es.submit(task3); 67 System.out.println("task3: " + future3.get()); 68 } catch (Exception e){ 69 System.out.println(e.toString()); 70 } 71 72 // 停止任務執行服務 73 es.shutdownNow(); 74 75 } 76 77 } View Code
?
- 線程控制:
1 // 線程控制 2 3 join()線程---必須等線程th執行完成后才能繼續向下執行 4 ... 5 th.start(); 6 th.join(); 7 ... 8 9 yield()禮讓---注意和線程通信中wait()區分,yield將線程放到就緒隊列,而wait將其放到阻塞隊列 10 ...th.doSomething... 11 th.yield(); 12 ...th.doSomethingElse... 13 14 sleep()睡眠---線程睡眠,將進入阻塞隊列 15 ...doSomething... 16 Thread.sleep(1000); 17 ...continueDoSomething... 18 19 setDaemon()后臺線程---將線程設置為后臺線程,將在前臺線程都死亡后自動死亡 20 .... 21 th.setDaemon(true); 22 .... 23 24 setPrority()優先級---設置優先級 25 ... 26 th.setPrority(5); 27 th.start(); 28 ... View Code
- 線程同步的3種實現:
1 /* 線程同步的3種實現: 2 * 1.同步代碼塊:鎖對象可以是任意對象 3 synchronized(obj){同步代碼塊} 4 * 2.同步方法: 5 2.1 普通同步方法,鎖對象是this 6 public synchronized void fun(){...} 7 2.2 靜態同步方法,鎖對象是.class字節碼對象 8 public static synchronized void fun(){...} 9 3.同步鎖:javaAPI提供了多種鎖,如讀寫鎖等,以及一些工具類的鎖(同時具有同步和通訊特點) 10 private Lock lock=new ReentrantLock(); 11 ... 12 lock.lock(); 13 ...doSomething... 14 lock.unLock(); 15 * 16 * 17 *以下著重介紹幾種工具類的鎖使用: 18 Samaphore 19 CyclicBarrier 20 CountDownLatch 21 */ 22 /** 23 * 線程互斥與通信: 24 * 線程通訊之傳統線程通訊: Semaphore信號燈工具 25 * 傳統的互斥,是由線程本身來控制鎖的占有和釋放,這就導致必須當前線程完成,或是主動讓出鎖,下一個線程才有機會, 26 * 而semaphore工具, 提供相當于專門的鎖的管理方全權控制索,任何線程的請求都通過管理方的許可,這樣就解放了鎖的控制權,讓多個線程共享鎖 27 * 28 *共有3盞燈,一次來了10個人,只用其中的3個人能夠拿到等,當有燈還回的時候,等候隊列的人才有機會拿到燈 29 *可用于死鎖恢復的一些場景 30 * 31 * @throws Exception 32 * @author ware E-mail: 33 * @version create time: 20172017年3月1日下午11:35:41 34 */ 35 public class ThreadCommunication3 { 36 37 public static void main(String[] args) { 38 final Semaphore sp=new Semaphore(3, true); 39 40 ExecutorService pool = Executors.newCachedThreadPool(); 41 42 for (int i = 0; i < 10; i++) { 43 Runnable task=new Runnable() { 44 @Override 45 public void run() { 46 try { 47 sp.acquire(); // 請求鎖 48 } catch (InterruptedException e) { 49 e.printStackTrace(); 50 } 51 System.out.println("線程"+Thread.currentThread().getName()+"已經進入---可用數"+(3-sp.availablePermits())); 52 53 try { 54 Thread.sleep(1000); 55 } catch (InterruptedException e) { 56 e.printStackTrace(); 57 } 58 59 System.out.println("線程"+Thread.currentThread().getName()+"準備離開"); 60 61 sp.release(); //釋放鎖 62 } 63 }; 64 65 pool.submit(task); 66 } 67 68 } 69 70 71 } 72 73 /** 74 * 線程互斥與通信: 75 * 線程通訊之傳統線程通訊: CyclicBarrier工具 76 * 所有規定的線程必須都在完成某一項工作之后才能繼續下一項工作 77 * 78 * 如: 班級郊游,只有所有的人都到了集合點(工作1)才能出發(工作2) 79 * 80 * @throws Exception 81 * @author ware E-mail: 82 * @version create time: 20172017年3月1日下午11:35:41 83 */ 84 public class ThreadCommunication4 { 85 86 public static void main(String[] args) { 87 final CyclicBarrier cb=new CyclicBarrier(4); // 約定有多少個人 88 89 ExecutorService pool = Executors.newCachedThreadPool(); 90 91 for (int i = 0; i < 4; i++) { 92 Runnable task=new Runnable() { 93 @Override 94 public void run() { 95 96 try { 97 // 第一階段工作 98 Thread.sleep((long) (Math.random()*1000)); 99 System.out.println(Thread.currentThread().getName()+"到達集合點,當前共有"+cb.getNumberWaiting()+"人在等待"); 100 cb.await(); 101 102 // 第二階段工作 103 Thread.sleep((long) (Math.random()*1000)); 104 System.out.println(Thread.currentThread().getName()+"出發中"+cb.getNumberWaiting()+"人出發中"); 105 cb.await(); 106 107 // 第三階段工作 108 Thread.sleep((long) (Math.random()*1000)); 109 System.out.println(Thread.currentThread().getName()+"到達景點"+cb.getNumberWaiting()+"人到達景點"); 110 cb.await(); 111 112 } catch (Exception e) { 113 e.printStackTrace(); 114 } 115 116 } 117 118 }; 119 120 pool.submit(task); 121 } 122 123 } 124 125 } 126 127 /** 128 * 線程互斥與通信: 129 * 線程通訊之傳統線程通訊: CountDownLatch工具 130 * 如同一個倒計時器,當countDown()到0的時候,所有等該"計時器"的線程都會受到消息 131 * 132 * 如: 所有的運動員都在等裁判的命令,裁判一聲令下,所有的運動員收到消息開始跑,裁判等到所有的人都跑到終點了才宣布結構 133 * 134 * @throws Exception 135 * @author ware E-mail: 136 * @version create time: 20172017年3月1日下午11:35:41 137 */ 138 public class ThreadCommunication6 { 139 140 public static void main(String[] args) { 141 final CountDownLatch cdOrder=new CountDownLatch(1); // 裁判命令 142 final CountDownLatch cdAnswer=new CountDownLatch(4); // 運動員的消息狀態 143 144 ExecutorService pool = Executors.newCachedThreadPool(); 145 146 // 4個運動員 147 for (int i = 0; i < 4; i++) { 148 Runnable task=new Runnable() { 149 @Override 150 public void run() { 151 152 try { 153 System.out.println(Thread.currentThread().getName()+"---已經準備好了,等待命令"); 154 155 cdOrder.await(); // 等命令 156 157 System.out.println("等到命令并開跑"); 158 Thread.sleep((long) (Math.random()*1000)); 159 System.out.println(Thread.currentThread().getName()+"跑完全程了"); 160 161 cdAnswer.countDown(); 162 163 } catch (Exception e) { 164 e.printStackTrace(); 165 } 166 167 } 168 169 }; 170 171 pool.submit(task); 172 } 173 174 175 // 1個裁判 176 Runnable coach=new Runnable() { 177 @Override 178 public void run() { 179 try { 180 System.out.println(Thread.currentThread().getName()+"準備開炮.....碰..."); 181 cdOrder.countDown(); 182 System.out.println(Thread.currentThread().getName()+"命令已發出,等待結果..."); 183 184 cdAnswer.await(); 185 System.out.println(Thread.currentThread().getName()+"比賽結束,成績出來了"); 186 187 } catch (InterruptedException e) { 188 e.printStackTrace(); 189 } 190 191 } 192 }; 193 pool.submit(coach); 194 195 196 } 197 198 199 } View Code
?
- 線程通訊:
1 /* 2 *3種線程通訊: 3 1. 傳統線程通訊--wait(),notify(); 4 2. Condition線程通訊; 5 2. BlockingQueue阻塞隊列 6 * 7 */ 8 /** 9 * 線程互斥與通信: 10 * 線程通訊之傳統線程通訊: wait(),notify(),notifyAll()(必須配合synchronized關鍵字) 11 * 12 *父線程執行10次, 13 *子線程執行50次 14 * @author ware E-mail: 15 * @version create time: 20172017年3月1日下午11:35:41 16 */ 17 public class ThreadCommunication { 18 private static boolean isSub=false; 19 20 public synchronized void doit(){ 21 while(true){ 22 while(isSub){ 23 try { 24 this.wait(); 25 } catch (InterruptedException e) { 26 e.printStackTrace(); 27 } 28 } 29 try { 30 Thread.sleep(1000); 31 } catch (InterruptedException e) { 32 e.printStackTrace(); 33 } 34 for (int i = 0; i < 10; i++) { 35 System.out.println("main"+"----------"+i); 36 } 37 isSub=true; 38 this.notify(); 39 } 40 41 } 42 public synchronized void doit2(){ 43 while(true){ 44 while(!isSub){ 45 try { 46 this.wait(); 47 } catch (InterruptedException e) { 48 e.printStackTrace(); 49 } 50 } 51 try { 52 Thread.sleep(1000); 53 } catch (InterruptedException e) { 54 // TODO Auto-generated catch block 55 e.printStackTrace(); 56 } 57 for (int i = 0; i < 50; i++) { 58 System.out.println("sub"+"----------"+i); 59 } 60 isSub=false; 61 this.notify(); 62 } 63 } 64 65 public static void main(String[] args) { 66 ThreadCommunication tc=new ThreadCommunication(); 67 68 // 父線程 69 Thread fatherTh=new Thread(){ 70 @Override 71 public void run() { 72 tc.doit(); 73 } 74 }; 75 76 // 子線程 77 Thread sonTh=new Thread(){ 78 @Override 79 public void run() { 80 tc.doit2(); 81 } 82 }; 83 84 fatherTh.start(); 85 sonTh.start(); 86 } 87 } 88 89 /** 90 * 線程互斥與通信: 91 * 線程通訊之傳統線程通訊: Condition(必須配合Lock使用) 92 93 * 是對阻塞隊列的實現: ArrayBlockQueue 94 * @throws Exception 95 * @author ware E-mail: 96 * @version create time: 20172017年3月1日下午11:35:41 97 */ 98 public class ThreadCommunication2 { 99 100 private static final Lock lock=new ReentrantLock(); 101 private static final Condition notFull=lock.newCondition(); 102 private static final Condition notEmpty=lock.newCondition(); 103 104 private Object resources[]; 105 106 int putIndex; // 下一個可取的資源索引 107 int takeIndex; // 下一個可以存放資源的索引 108 int count; // 當前總資源數 109 110 public ThreadCommunication2(int resourceLimit) { 111 resources=new Object[resourceLimit]; 112 this.putIndex=0; 113 this.takeIndex=0; 114 this.count=0; 115 } 116 117 public void put(Object taskResource){ 118 lock.lock(); 119 try { 120 while(count==resources.length){ 121 notFull.await(); 122 } 123 System.out.println("-----------------put"); 124 resources[putIndex]=taskResource; 125 putIndex=(putIndex%resources.length); 126 count++; 127 notEmpty.signalAll(); 128 } catch (Exception e) { 129 e.printStackTrace(); 130 }finally{ 131 lock.unlock(); 132 } 133 } 134 135 public Object take(){ 136 Object result=null; 137 lock.lock(); 138 try { 139 while(count==0){ 140 notEmpty.await(); 141 } 142 System.out.println("----------------take"); 143 result=resources[takeIndex]; 144 takeIndex=(takeIndex+1)%resources.length; 145 count--; 146 147 notFull.signalAll(); 148 } catch (Exception e) { 149 e.printStackTrace(); 150 }finally{ 151 lock.unlock(); 152 } 153 154 return result; 155 } 156 157 158 public static void main(String[] args) { 159 ThreadCommunication2 tc=new ThreadCommunication2(7); // 資源隊列的長度為7 160 161 // 開10個放線程 162 for (int i = 0; i < 10; i++) { 163 new Thread(new Runnable() { 164 @Override 165 public void run() { 166 tc.put(Thread.currentThread().getName()); 167 } 168 }).start(); 169 } 170 171 // 開10個拿線程 172 for (int i = 0; i < 10; i++) { 173 new Thread(new Runnable() { 174 @Override 175 public void run() { 176 System.out.println(tc.take()); 177 } 178 }).start(); 179 } 180 } 181 182 } 183 184 185 /** 186 *BlockingQueue阻塞隊列 187 *放線程在隊列滿的時候直接放棄,通知拿線程,然后進入阻塞隊列, 188 *拿線程在隊列空的時候直接放棄,通知放線程,然后進入阻塞隊列, 189 */ 190 public class DequeueTest { 191 192 private final static BlockingQueue<Object> queue=new ArrayBlockingQueue<>(5); 193 194 public static void main(String[] args) throws InterruptedException { 195 196 // 開10個放線程 197 for (int i = 0; i < 10; i++) { 198 new Thread(new Runnable() { 199 @Override 200 public void run() { 201 queue.add(Thread.currentThread().getName()); 202 } 203 }).start(); 204 } 205 206 // 開10個拿線程 207 for (int i = 0; i < 10; i++) { 208 new Thread(new Runnable() { 209 @Override 210 public void run() { 211 System.out.println(queue.remove()); 212 } 213 }).start(); 214 } 215 216 } 217 218 } View Code
- 線程數據共享:
1 /* 線程數據共享: 2 * 1.多個線程間共享同一個數據: 3 1.1.多個線程的執行代碼相同---多個線程共用一個Runnable的實例, 那么Runnable中的類成員將被共享; 4 * 1.2.多個線程的執行代碼不同---為多個Runnable對象傳入同一個實體對象 5 * 1.3.多個線程的執行代碼不同---將多個Runnable設置為內部類,將共享實體設置為外部類成員變量 6 * 2.一個線程的多個代碼塊共享一個數據: 7 * 2.1 將 (線程,數據對象) 放到一個map中, 8 * 2.2 一般使用java類庫提供的ThreadLocal,實現原理同上,但是更優雅,而且會在線程結束后自動清理 9 * 10 * 線程間的數據共享比較簡單,這里著重介紹線程內的數據共享 11 */ 12 /** 13 * 線程范圍內的共享:多個模塊在同一個線程中運行時要共享一份數據 14 * 15 * 解決方式: 使用ThreadLocal---優雅版---將線程與數據分離 16 * 17 * @param 18 * @return 19 * @throws Exception 20 * @author ware E-mail: 21 * @version create time: 20172017年3月2日上午9:07:16 22 */ 23 public class ThreadScopeShared4 { 24 // private static ThreadLocal<Integer> local=new ThreadLocal<>(); 25 26 public static void main(String[] args) { 27 for (int i = 0; i < 3; i++) { 28 new Thread(new Runnable() { 29 @Override 30 public void run() { 31 // int data=new Random().nextInt(); 32 // local.set(data); 33 34 ThreadScopeSharedData.getInstance().setAge(new Random().nextInt()); 35 ThreadScopeSharedData.getInstance().setName("vivi"); 36 new A().getNum(); 37 new B().getNum(); 38 } 39 }).start(); 40 } 41 42 } 43 44 static class A{ // 模塊A 45 public void getNum(){ 46 int age=ThreadScopeSharedData.getInstance().getAge(); 47 String name=ThreadScopeSharedData.getInstance().getName(); 48 System.out.println(Thread.currentThread().getName()+"---------"+age); 49 } 50 } 51 static class B{ // 模塊B 52 public void getNum(){ 53 int age=ThreadScopeSharedData.getInstance().getAge(); 54 String name=ThreadScopeSharedData.getInstance().getName(); 55 System.out.println(Thread.currentThread().getName()+"---------"+age); 56 } 57 } 58 } 59 60 // 專門與線程綁定的對象 61 class ThreadScopeSharedData{ 62 private ThreadScopeSharedData() {} 63 public static ThreadScopeSharedData getInstance(){ 64 ThreadScopeSharedData instance=map.get(); 65 if(instance==null){ 66 instance=new ThreadScopeSharedData(); 67 map.set(instance); 68 } 69 return instance; 70 } 71 72 private static ThreadLocal<ThreadScopeSharedData> map=new ThreadLocal<>(); 73 74 private int age; 75 private String name; 76 public int getAge() { 77 return age; 78 } 79 public void setAge(int age) { 80 this.age = age; 81 } 82 public String getName() { 83 return name; 84 } 85 public void setName(String name) { 86 this.name = name; 87 } 88 89 90 } View Code
- ?線程池:
- 詳細:http://www.cnblogs.com/murthy/p/6495340.html
轉載于:https://www.cnblogs.com/murthy/p/6509433.html
總結
- 上一篇: EventBus使用实例,观察者模式
- 下一篇: Linux下安装配置MySQL