線程安全---Day23

最近忙着備考大學四年最後的兩科,昨天剛考完大學全部的考試,可是大學專業是機械,可是本身熱衷於IT行業,想往IT行業走,但願畢業後能成功進入到IT行業,只但願畢業能找到一份Java開發工程師的工做,這樣我才能專研和學習到更高深的技術.但願在畢業前能學到一點Java的精髓,讓我能夠成功進入到IT行業,加油~java


 

線程問題:安全

 1 package demosummary.threadsafety;  2 
 3 public class Ticket implements Runnable{  4     //定義票數
 5     private int ticket = 100;  6     /**
 7  * 執行賣票方法  8      */
 9  @Override 10     public void run() { 11         //賣票窗口永久開啓
12         while (true) { 13             //判斷票是否賣完
14             if (ticket > 0) { 15                 try { 16                     //三秒賣一張票
17                     Thread.sleep(3000); 18                 } catch (InterruptedException e) { 19  e.printStackTrace(); 20  } 21                 String name = Thread.currentThread().getName(); 22                 System.out.println(name+"正在賣:"+ticket--); 23  } 24  } 25  } 26 } 27 
28 
29 
30 
31 package demosummary.threadsafety; 32 
33 public class TicketTest { 34     public static void main(String[] args) { 35         //建立線程任務對象
36         Ticket ticket = new Ticket(); 37         //建立三個窗口對象
38         Thread t1 = new Thread(ticket, "窗口1"); 39         Thread t2 = new Thread(ticket, "窗口2"); 40         Thread t3 = new Thread(ticket, "窗口3"); 41         //啓用窗口來賣票
42  t1.start(); 43  t2.start(); 44  t3.start(); 45  } 46     /**
47  * 執行結果 48  * 窗口2正在賣:79 49  * 窗口3正在賣:79 50  * 窗口1正在賣:-1 51  * 出現重複賣同一張票和負票,在現實中是不容許出現的 52      */
53 }

  注意:執行結果出現兩種問題多線程

    1.出現不一樣窗口賣同一張票,把票賣了兩次併發

    2.出現賣不存在的票ide

  注意:這兩種問題稱爲線程不安全學習

  線程安全問題都是由全局變量及靜態變量引發的。若每一個線程中對全局變量、靜態變量只有讀操做,而無寫 操做,通常來講,這個全局變量是線程安全的;如有多個線程同時執行寫操做,通常都須要考慮線程同步, 不然的話就可能影響線程安全this

線程同步spa

  當咱們使用多個線程訪問同一資源的時候,且多個線程中對資源有寫的操做,就容易出現線程安全問題。要解決上述多線程併發訪問一個資源的安全性問題:也就是解決重複票與不存在票問題,Java中提供了同步機制 (synchronized)來解決線程

  方法:code

    1. 同步代碼塊

    2. 同步方法

    3. 鎖機制

同步代碼塊

  同步代碼塊: synchronized 關鍵字能夠用於方法中的某個區塊中,表示只對這個區塊的資源實行互斥訪問

  格式:

    synchronized(同步鎖){

      須要同步操做的代碼

    }

  同步鎖:對象的同步鎖只是一個概念,能夠想象爲在對象上標記了一個鎖

    1. 鎖對象 能夠是任意類型。

    2. 多個線程對象  要使用同一把鎖

  同步鎖是誰?

    對於非static方法,同步鎖就是this。 

    對於static方法,咱們使用當前方法所在類的字節碼對象(類名.class)。

  注意:在任什麼時候候,最多容許一個線程擁有同步鎖,誰拿到鎖就進入代碼塊,其餘的線程只能在外等着 (BLOCKED)

 1 package demosummary.threadsafety;  2 
 3 public class Ticket02 implements Runnable {  4     //定義票數
 5     private int ticket = 100;  6 
 7     Object lock = new Object();  8     /**
 9  * 執行賣票方法 10      */
11  @Override 12 
13     public void run() { 14         //賣票窗口永久開啓
15         while (true) { 16             synchronized (lock) { 17                 //判斷票是否賣完
18                 if (ticket > 0) { 19                     try { 20                         //三秒賣一張票
21                         Thread.sleep(3000); 22                     } catch (InterruptedException e) { 23  e.printStackTrace(); 24  } 25                     String name = Thread.currentThread().getName(); 26                     System.out.println(name + "正在賣:" + ticket--); 27  } 28  } 29  } 30  } 31 } 32 
33 package demosummary.threadsafety; 34 
35 public class TicketTest02 { 36     public static void main(String[] args) { 37         //建立線程任務對象
38         Ticket02 ticket = new Ticket02(); 39         //建立三個窗口對象
40         Thread t1 = new Thread(ticket, "窗口1"); 41         Thread t2 = new Thread(ticket, "窗口2"); 42         Thread t3 = new Thread(ticket, "窗口3"); 43         //啓用窗口來賣票
44  t1.start(); 45  t2.start(); 46  t3.start(); 47  } 48 }

  使用了同步代碼塊能夠解決線程安全問題

同步方法

  同步方法:使用synchronized修飾的方法,就叫作同步方法,保證A線程執行該方法的時候,其餘線程只能在方法外等着。

  格式:

    public synchronized void method(){     

      可能會產生線程安全問題的代碼   

    }

 1 package demosummary.threadsafety;  2 
 3 public class Ticket03 implements Runnable {  4     private int ticket = 100;  5 
 6     /**
 7  * 執行賣票方法  8      */
 9  @Override 10     public void run() { 11         //賣票窗口永久開啓
12         while (true) { 13  sellTicket(); 14  } 15  } 16 
17     private synchronized void sellTicket() { 18         //判斷票是否賣完
19         if (ticket > 0) { 20             try { 21                 //三秒賣一張票
22                 Thread.sleep(3000); 23             } catch (InterruptedException e) { 24  e.printStackTrace(); 25  } 26             //獲取線程名稱
27             String name = Thread.currentThread().getName(); 28             System.out.println(name + "正在賣:" + ticket--); 29  } 30  } 31 } 32 
33 
34 
35 package demosummary.threadsafety; 36 
37 public class TicketTest03 { 38     public static void main(String[] args) { 39         //建立線程任務對象
40         Ticket03 ticket = new Ticket03(); 41         //建立三個窗口對象
42         Thread t1 = new Thread(ticket, "窗口1"); 43         Thread t2 = new Thread(ticket, "窗口2"); 44         Thread t3 = new Thread(ticket, "窗口3"); 45         //啓用窗口來賣票
46  t1.start(); 47  t2.start(); 48  t3.start(); 49  } 50 }

Lock鎖

  java.util.concurrent.locks.Lock 機制提供了比synchronized代碼塊和synchronized方法更普遍的鎖定操做, 同步代碼塊/同步方法具備的功能Lock都有,除此以外更強大,更體現面向對象

  Lock鎖也稱同步鎖,加鎖與釋放鎖方法化了,以下

    public void lock() :加同步鎖。

    public void unlock() :釋放同步

 1 package demosummary.threadsafety;  2 
 3 import java.util.concurrent.locks.Lock;  4 import java.util.concurrent.locks.ReentrantLock;  5 
 6 public class Ticket04 implements Runnable {  7     //定義票數
 8     private int ticket = 100;  9 
10     //建立鎖對象
11     Lock lock = new ReentrantLock(); 12     /**
13  * 執行賣票方法 14      */
15  @Override 16     public void run() { 17         //賣票窗口永久開啓
18         while (true) { 19             //給線程加鎖
20  lock.lock(); 21             //判斷是否郵票可賣
22             if (ticket > 0) { 23                 try { 24                     Thread.sleep(1000); 25                 } catch (InterruptedException e) { 26  e.printStackTrace(); 27  } 28                 //獲取線程當前名稱
29                 String name = Thread.currentThread().getName(); 30                 System.out.println(name+"正在賣"+ticket--); 31  } 32             //釋放線程鎖
33  lock.unlock(); 34  } 35  } 36 } 37 
38 package demosummary.threadsafety; 39 
40 public class TicketTest04 { 41     public static void main(String[] args) { 42         //建立線程任務對象
43         Ticket04 ticket = new Ticket04(); 44         //建立三個窗口對象
45         Thread t1 = new Thread(ticket, "窗口1"); 46         Thread t2 = new Thread(ticket, "窗口2"); 47         Thread t3 = new Thread(ticket, "窗口3"); 48         //啓用窗口來賣票
49  t1.start(); 50  t2.start(); 51  t3.start(); 52  } 53 }
相關文章
相關標籤/搜索