synchronized關鍵字的詳細分析和代碼實例
阿新 • • 發佈:2019-04-19
win 等待 必須 sta ack 安全問題 ont style thread類
在Java中,一般都是通過同步機制來解決線程安全問題的,在JDK 5.0之後又新增了Lock的方式來實現線程安全。所以說實現線程安全方式一共有三種方法
方式一:
synchronized(同步監視器){
//需要被同步的代碼(操作共享數據的代碼就是需要被同步的代碼)
}
通過繼承Thread類的方式實現多線程並解決線程安全問題:
1 package com.baozi.java; 2 3 public class WinowTest { 4 public static void main(String[] args){ 5 Window w1=newWindow(); 6 Window w2=new Window(); 7 Window w3=new Window(); 8 w1.start(); 9 w2.start(); 10 w3.start(); 11 } 12 } 13 //通過繼承Thread類的方法來實現多線程 14 class Window extends Thread { 15 private static int ticket = 100; 16 @Override 17 publicvoid run() { 18 while (true) { 19 //這裏通過synchronized代碼塊的形式來實現線程安全 20 synchronized (Window.class) { 21 if (ticket > 0) { 22 try { 23 Thread.sleep(100); 24 } catch (InterruptedException e) {25 e.printStackTrace(); 26 } 27 System.out.println(Thread.currentThread().getName() + ":" + ticket--); 28 } else { 29 break; 30 } 31 } 32 } 33 34 } 35 }
通過實現Runnable接口的方式實現多線程並解決線程安全問題:
1 package com.baozi.java; 2 3 public class WindowTest2 { 4 public static void main(String[] args){ 5 Window2 window2 = new Window2(); 6 Thread t1 = new Thread(window2); 7 Thread t2 = new Thread(window2); 8 t1.setName("線程1"); 9 t2.setName("線程2"); 10 t1.start(); 11 t2.start(); 12 } 13 14 } 15 //通過實現Runnable接口的方式實現多線程 16 class Window2 implements Runnable{ 17 private int ticket = 100; 18 @Override 19 public void run() { 20 while (true) { 21 //這裏通過synchronized代碼塊的形式來實現線程安全 22 synchronized (this) { 23 if (ticket > 0) { 24 try { 25 Thread.sleep(100); 26 } catch (InterruptedException e) { 27 e.printStackTrace(); 28 } 29 System.out.println(Thread.currentThread().getName() + ":" + ticket--); 30 } else { 31 break; 32 } 33 } 34 } 35 36 } 37 }
備註:
同步監視器:其實就是我們平時說的鎖,任何一個類對象都可以充當同步監視器,並且針對需要操作的共享數據,要求多個線程必須共享同一個同步監視器,這樣才能實現多線程共享數據的線程安全。
同步方法解決了線程安全問題,但是在操作同步代碼塊的時候,實質上某一時刻只有一個線程擁有鎖,其他線程需要操作共享數據的時候只能等待該線程釋放了所之後通過搶占方式獲得鎖之後才能執行。言外之意針對共享數據其實是單線程執行,這樣會造成效率非常低。
方式二:
如果多個線程操作的共享數據的代碼完整的聲明在一個方法中,那麽我們使用synchronized關鍵字修飾這個方法為同步方法。
通過繼承Thread類的方式實現多線程並解決線程安全問題:
1 package com.baozi.java; 2 3 public class WindowTest3 { 4 public static void main(String[] args) { 5 Window3 w1 = new Window3(); 6 Window3 w2 = new Window3(); 7 Window3 w3 = new Window3(); 8 w1.start(); 9 w2.start(); 10 w3.start(); 11 } 12 } 13 14 //通過繼承Thread類的方法來實現多線程 15 class Window3 extends Thread { 16 private static int ticket = 100; 17 18 @Override 19 public void run() { 20 while (true) { 21 show(); 22 } 23 } 24 25 //這裏通過synchronized方法的形式來實現線程安全 26 public static synchronized void show() { 27 if (ticket > 0) { 28 try { 29 Thread.sleep(100); 30 } catch (InterruptedException e) { 31 e.printStackTrace(); 32 } 33 System.out.println(Thread.currentThread().getName() + ":" + ticket--); 34 } 35 } 36 }
通過實現Runnable接口的方式實現多線程並解決線程安全問題:
1 package com.baozi.java; 2 3 public class WindowTest2 { 4 public static void main(String[] args) { 5 Window2 window2 = new Window2(); 6 Thread t1 = new Thread(window2); 7 Thread t2 = new Thread(window2); 8 t1.setName("線程1"); 9 t2.setName("線程2"); 10 t1.start(); 11 t2.start(); 12 } 13 } 14 //通過實現Runnable接口的方式實現多線程 15 class Window2 implements Runnable { 16 private int ticket = 100; 17 18 @Override 19 public synchronized void run() { 20 while (true) { 21 if (ticket > 0) { 22 try { 23 Thread.sleep(100); 24 } catch (InterruptedException e) { 25 e.printStackTrace(); 26 } 27 System.out.println(Thread.currentThread().getName() + ":" + ticket--); 28 } else { 29 break; 30 } 31 } 32 } 33 }
備註:同步方法依然會涉及到同步監視器,只是不需要我麽顯示的聲明。
非靜態的同步方法:同步監視器可以是this(當前對象)
靜態的同步方法:同步監視器可以是當前類
這樣我們就能省去單獨造一個對象來充當同步監視器,使代碼比較簡單整潔。
方式三:
使用Lock鎖的方式實現線程安全,這是JDK5.0新增加的方法,在後邊單獨分析。
synchronized關鍵字的詳細分析和代碼實例