在Java中,同步是一種控制多線程訪問共享資源的能力。當咱們只容許一個線程訪問共享資源時同步是最好的選擇。同步通常用來解決兩個問題:1.防止線程干擾2.防止一致性問題。同步分兩類:1.進程(Process)同步2.線程(Thread)同步。這裏咱們只討論Java中線程同步。html
當咱們在一個程序中啓動兩個或兩個以上線程時,可能會有一種狀況:當多個線程試圖訪問相同的資源時因爲併發問題會產生沒法預料的結果。舉個例子:若是多個線程同時寫同一個文件它們可能會破壞數據,由於其中一個線程會覆蓋數據,或者當一個線程打開文件的同時另外一個線程正在關閉該文件。git
因此多線程要考慮同步問題,確保同一時間只有一個線程能夠訪問資源。這裏就會有一個概念叫監視器(monitors),每一個對象(object)在Java中都關聯一個監視器,每一個線程均可以加鎖(lock)和解鎖(unlock),但同一時間只有一個線程能夠給監視器加鎖或解鎖。github
Java提供了一種很是簡單的方式來建立和同步任務代碼塊:經過使用synchronized關鍵字。下面是同步的通常方式:算法
1 synchronized(objectidentifier) { 2 // 訪問共享變量和其它共享資源 3 }
這裏的objectidentifier指的是獲取了鎖的監視器的對象。下來咱們寫兩個例子,咱們將使用兩個不一樣的線程打印一個計數器。當沒有線程同步時不是按順序打印計數器的值,當使用synchronized()同步代碼塊時能夠看到計數器打印的值是有序的。多線程
多線程示例:沒有同步代碼塊併發
這是一個簡單的例子。它可能但不必定會按順序打印出計數器的值,這是由CPU的可用性決定的。ide
1 class PrintDemo { 2 public void printCount() { 3 try { 4 for(int i = 5; i > 0; i--) { 5 System.out.println("Counter --- " + i ); 6 } 7 }catch (Exception e) { 8 System.out.println("Thread interrupted."); 9 } 10 } 11 } 12 13 class ThreadDemo extends Thread { 14 private Thread t; 15 private String threadName; 16 PrintDemo PD; 17 18 ThreadDemo( String name, PrintDemo pd) { 19 threadName = name; 20 PD = pd; 21 } 22 23 public void run() { 24 PD.printCount(); 25 System.out.println("Thread " + threadName + " exiting."); 26 } 27 28 public void start () { 29 System.out.println("Starting " + threadName ); 30 if (t == null) { 31 t = new Thread (this, threadName); 32 t.start (); 33 } 34 } 35 } 36 37 public class TestThread { 38 public static void main(String args[]) { 39 40 PrintDemo PD = new PrintDemo(); 41 42 ThreadDemo T1 = new ThreadDemo( "Thread - 1 ", PD ); 43 ThreadDemo T2 = new ThreadDemo( "Thread - 2 ", PD ); 44 45 T1.start(); 46 T2.start(); 47 48 // wait for threads to end 49 try { 50 T1.join(); 51 T2.join(); 52 }catch( Exception e) { 53 System.out.println("Interrupted"); 54 } 55 } 56 }
執行上面的代碼每次運行的結果可能不同,因此不能保證咱們按順序打印計數器。this
多線程示例:使用同步代碼塊spa
下面是一樣的一個例子,不過咱們加了synchronized()同步代碼塊,這樣它每次都能按順序打印相同的值。操作系統
1 class PrintDemo { 2 public void printCount() { 3 try { 4 for(int i = 5; i > 0; i--) { 5 System.out.println("Counter --- " + i ); 6 } 7 }catch (Exception e) { 8 System.out.println("Thread interrupted."); 9 } 10 } 11 } 12 13 class ThreadDemo extends Thread { 14 private Thread t; 15 private String threadName; 16 PrintDemo PD; 17 18 ThreadDemo( String name, PrintDemo pd) { 19 threadName = name; 20 PD = pd; 21 } 22 23 public void run() { 24 synchronized(PD) { 25 PD.printCount(); 26 } 27 System.out.println("Thread " + threadName + " exiting."); 28 } 29 30 public void start () { 31 System.out.println("Starting " + threadName ); 32 if (t == null) { 33 t = new Thread (this, threadName); 34 t.start (); 35 } 36 } 37 } 38 39 public class TestThread { 40 41 public static void main(String args[]) { 42 PrintDemo PD = new PrintDemo(); 43 44 ThreadDemo T1 = new ThreadDemo( "Thread - 1 ", PD ); 45 ThreadDemo T2 = new ThreadDemo( "Thread - 2 ", PD ); 46 47 T1.start(); 48 T2.start(); 49 50 // wait for threads to end 51 try { 52 T1.join(); 53 T2.join(); 54 }catch( Exception e) { 55 System.out.println("Interrupted"); 56 } 57 } 58 }
執行上面的代碼每次打印的結果都同樣:按順序輸出計數器的值。
Java多任務處理都會有併發執行狀況,多個任務或進程共享一個CPU,並交由操做系統來完成多任務間對CPU的運行切換,以使得每一個任務都有機會得到必定的時間片運行。下面是併發和並行的區別:Concurrent and Parallel Programming
併發:兩個隊列一個咖啡機。一個CPU處理多個任務邏輯,經過CPU調度算法分配計算資源,非真正的同時進行。
並行:兩個隊列兩個咖啡機。多個CPU處理多個任務邏輯,多個計算任務能夠同時進行。