synchronized關鍵字的詳細分析和代碼實例

  在Java中,通常都是經過同步機制來解決線程安全問題的,在JDK 5.0以後又新增了Lock的方式來實現線程安全。因此說實現線程安全方式一共有三種方法java

方式一:安全

synchronized(同步監視器){多線程

  //須要被同步的代碼(操做共享數據的代碼就是須要被同步的代碼)ide

}this

經過繼承Thread類的方式實現多線程並解決線程安全問題:spa

 1 package com.baozi.java;
 2 
 3 public class WinowTest {
 4     public static void main(String[] args){
 5         Window w1=new Window();
 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     public void 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 }

備註:code

  同步監視器:其實就是咱們平時說的鎖,任何一個類對象均可以充當同步監視器,而且針對須要操做的共享數據,要求多個線程必須共享同一個同步監視器,這樣才能實現多線程共享數據的線程安全。對象

  同步方法解決了線程安全問題,可是在操做同步代碼塊的時候,實質上某一時刻只有一個線程擁有鎖,其餘線程須要操做共享數據的時候只能等待該線程釋放了所以後經過搶佔方式得到鎖以後才能執行。言外之意針對共享數據實際上是單線程執行,這樣會形成效率很是低。blog

方式二:

若是多個線程操做的共享數據的代碼完整的聲明在一個方法中,那麼咱們使用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新增長的方法,在後邊單獨分析。

相關文章
相關標籤/搜索