1. 程式人生 > >Java多執行緒(三)、執行緒同步

Java多執行緒(三)、執行緒同步

在之前,已經學習到了執行緒的建立和狀態控制,但是每個執行緒之間幾乎都沒有什麼太大的聯絡。可是有的時候,可能存在多個執行緒多同一個資料進行操作,這樣,可能就會引用各種奇怪的問題。現在就來學習多執行緒對資料訪問的控制吧。

 由於同一程序的多個執行緒共享同一片儲存空間,在帶來方便的同時,也帶來了訪問衝突這個嚴重的問題。Java語言提供了專門機制以解決這種衝突,有效避免了同一個資料物件被多個執行緒同時訪問。


一、多執行緒引起的資料訪問安全問題

下面看一個經典的問題,銀行取錢的問題:

1)、你有一張銀行卡,裡面有5000塊錢,然後你到取款機取款,取出3000,當正在取的時候,取款機已經查詢到你有5000塊錢,然後正準備減去300塊錢的時候

2)、你的老婆拿著那張銀行卡對應的存摺到銀行取錢,也要取3000.然後銀行的系統查詢,存摺賬戶裡還有6000(因為上面錢還沒扣),所以它也準備減去3000,

3)、你的卡里面減去3000,5000-3000=2000,並且你老婆的存摺也是5000-3000=2000。

4)、結果,你們一共取了6000,但是卡里還剩下2000。

下面看程式的模擬過程:

[java]  view plain  copy
  1. package com.tao.test;  
  2.   
  3. public class GetMoneyTest {  
  4.     public static void main(String[] args) {  
  5.         Account account = new Account(5000);  
  6.         GetMoneyRun runnable = new
     GetMoneyRun(account);  
  7.         new Thread(runnable, "你").start();  
  8.         new Thread(runnable, "你老婆").start();  
  9.     }  
  10. }  
  11.   
  12. // 賬戶Mode  
  13. class Account {  
  14.     private int money;  
  15.   
  16.     public Account(int money) {  
  17.         super();  
  18.         this.money = money;  
  19.     }  
  20.   
  21.     public int getMoney() {  
  22.         return money;  
  23.     }  
  24.   
  25.     public void setMoney(int money) {  
  26.         this.money = money;  
  27.     }  
  28.   
  29. }  
  30. //runnable類  
  31. class GetMoneyRun implements Runnable {  
  32.     private Account account;  
  33.   
  34.     public GetMoneyRun(Account account) {  
  35.         this.account = account;  
  36.     }  
  37.   
  38.     @Override  
  39.     public void run() {  
  40.         if (account.getMoney() > 3000) {  
  41.             System.out.println(Thread.currentThread().getName() + "的賬戶有"  
  42.                     + account.getMoney() + "元");  
  43.             try {  
  44.                 Thread.sleep(10);  
  45.             } catch (InterruptedException e) {  
  46.                 e.printStackTrace();  
  47.             }  
  48.             int lasetMoney=account.getMoney() - 3000;  
  49.             account.setMoney(lasetMoney);  
  50.             System.out.println(Thread.currentThread().getName() + "取出來了3000元"  
  51.                     + Thread.currentThread().getName() + "的賬戶還有"  
  52.                     + account.getMoney() + "元");  
  53.   
  54.         } else {  
  55.             System.out.println("餘額不足3000" + Thread.currentThread().getName()  
  56.                     + "的賬戶只有" + account.getMoney() + "元");  
  57.         }  
  58.   
  59.     }  
  60.   
  61. }  
多次執行程式,可以看到有多種不同的結果,下面是其中的三種:

[java]  view plain  copy
  1. 你的賬戶有5000元  
  2. 你老婆的賬戶有5000元  
  3. 你老婆取出來了3000元你老婆的賬戶還有2000元  
  4. 你取出來了3000元你的賬戶還有-1000元  

[java]  view plain  copy
  1. 你的賬戶有5000元  
  2. 你老婆的賬戶有5000元  
  3. 你老婆取出來了3000元你老婆的賬戶還有-1000元  
  4. 你取出來了3000元你的賬戶還有-1000元  

[java]  view plain  copy
  1. 你的賬戶有5000元  
  2. 你老婆的賬戶有5000元  
  3. 你老婆取出來了3000元你老婆的賬戶還有2000元  
  4. 你取出來了3000元你的賬戶還有2000元  

可以看到,由於有兩個執行緒同時訪問這個account物件,導致取錢發生的賬戶發生問題。當多個執行緒訪問同一個資料的時候,非常容易引發問題。 為了避免這樣的事情發生,我們要保證執行緒同步互斥,所謂同步互斥就是:併發執行的多個執行緒在某一時間內只允許一個執行緒在執行以訪問共享資料。


二、同步互斥鎖

同步鎖的原理:Java中每個物件都有一個內建同步鎖。Java中可以使用synchronized關鍵字來取得一個物件的同步鎖。synchronized的使用方式,是在一段程式碼塊中,加上synchronized(object){ ... }

例如,有一個show方法,裡面有synchronized的程式碼段:

[java]  view plain  copy
  1. public void show() {  
  2.     synchronized(object){  
  3.        ......  
  4.     }  
  5. }  

這其中的object可以使任何物件,表示當前執行緒取得該物件的鎖。一個物件只有一個鎖,所以其他任何執行緒都不能訪問該物件的所有由synchronized包括的程式碼段,直到該執行緒釋放掉這個物件的同步鎖(釋放鎖是指持鎖執行緒退出了synchronized同步方法或程式碼塊)。

注意:synchronized使用方式有幾個要注意的地方(還是以上面的show方法舉例):

①、取得同步鎖的物件為this,即當前類物件,這是使用的最多的一種方式

[java]  view plain  copy
  1. public void show() {  
  2.     synchronized(this){  
  3.        ......  
  4.     }  
  5. }  


②、將synchronized加到方法上,這叫做同步方法,相當於第一種方式的縮寫
[java]  view plain  copy
  1. public synchronized void show() {  
  2.      
  3. }  


③、靜態方法的同步

[java]  view plain  copy
  1. public static synchronized void show() {  
  2.      
  3. }  
相當於

[java]  view plain  copy

    相關推薦

    Java執行執行同步

    在之前,已經學習到了執行緒的建立和狀態控制,但是每個執行緒之間幾乎都沒有什麼太大的聯絡。可是有的時候,可能存在多個執行緒多同一個資料進行操作,這樣,可能就會引用各種奇怪的問題。現在就來學習多執行緒對資料訪問的控制吧。  由於同一程序的多個執行緒共享同一片儲存空間,在帶來方便

    2.1.2.4Java執行執行

    系統啟動一個新執行緒的成本是比較高的,因為它涉及到與作業系統的互動。在這種情況下,使用執行緒池可以很好的提供效能,尤其是當程式中需要建立大量生存期很短暫的執行緒時,更應該考慮使用執行緒池。 與資料庫連線池類似的是,執行緒池在系統啟動時即建立大量空閒的執行緒,程

    Java執行執行

    系統啟動一個新執行緒的成本是比較高的,因為它涉及到與作業系統的互動。在這種情況下,使用執行緒池可以很好的提供效能,尤其是當程式中需要建立大量生存期很短暫的執行緒時,更應該考慮使用執行緒池。 與資料庫連線池類似的是,執行緒池在系統啟動時即建立大量空閒的執行緒,程式將一個Runnable物件傳給

    Java執行執行的生命週期和狀態控制

    、執行緒的生命週期 執行緒狀態轉換圖: 1、新建狀態 用new關鍵字和Thread類或其子類建立一個執行緒物件後,該執行緒物件就處於新生狀態。處於新生狀態的執行緒有自己的記憶體空間,通過呼叫start方法進入就緒狀態(runnable)。 注意:不能對已經啟動的

    執行 實現執行範圍內模組之間共享資料及執行間資料獨立ThreadLocal

           ThreadLocal為解決多執行緒程式的併發問題提供了一種新的思路。JDK 1.2的版本中就提供java.lang.ThreadLocal,使用這個工具類可以很簡潔地編寫出優美的多執行緒程式,ThreadLocal並不是一個Thread,而是Thread的區域

    Java線程SimpleDateFormat

    spa bsp sdf java多線程 ext add println turn static 多線程報錯:java.lang.NumberFormatException: multiple points SimpleDateFormat是非線程安全的,在多線程情況下會有

    java線程

    http acc system tle 線程編程 getname 定時 raw size 本文主要接著前面多線程的兩篇文章總結Java多線程中的線程安全問題。 一.一個典型的Java線程安全例子 1 public class ThreadTest { 2 3

    程序與執行——程序/執行間通訊

    在使用者空間中建立執行緒   用庫函式實現執行緒(《現代作業系統》 P61) #include<pthread.h> #include<stdio.h> #include<stdlib.h> #define NUMBER_OF_THREAD

    JAVA基礎23-執行【synchronized,ReentranLock,volatile死鎖】

    一、同步         大多數多執行緒應用中,兩個或兩個以上的執行緒需要共享對同一資料的存取,此時出現多個程式交替處理該資料,從而導致資料出現訛誤。 9-1.Synchronized關鍵字       &nb

    java 執行

    1、java 中任何物件都可以作為鎖 2、同步程式碼執行完成後會自動釋放掉 3、happend-before 4、類鎖和物件鎖相互幾乎不影響,不存在競爭 5、私有鎖和物件鎖不存在競爭,相互不影響 6、一個執行緒一旦呼叫wait()就釋放了所以的鎖,一個等待執行緒被notify()喚醒,不會立刻進入喚

    Python 執行程序 執行程序對比程序

    Python 多執行緒、多程序 (一)之 原始碼執行流程、GIL Python 多執行緒、多程序 (二)之 多執行緒、同步、通訊 Python 多執行緒、多程序 (三)之 執行緒程序對比、多執行緒 一、多執行緒與多程序的對比 在之前簡單的提過,CPython中的GIL使得同一時刻只能有一個執行緒執行,即併

    深入理解Java執行

    關於java多執行緒的概念以及基本用法:java多執行緒基礎 3, 執行緒間通訊 執行緒在作業系統中是獨立的個體,經過特殊的處理,執行緒間可以實現通訊,進而成為一個整體,提高CPU利用率 3.1,等待/通知機制 等待:wait()方法作用是使當前執

    java執行:建立執行種方式以及優缺點總結

    一、Java中建立執行緒主要有三種方式: 1、繼承Thread類建立執行緒類 步驟: (1)定義Thread類的子類,並重寫該類的run方法,該run方法的方法體就代表了執行緒要完成的任務。因此把run()方法稱為執行體。 (2)建立Thread子類的例項,即建立了執行緒物件。

    Java 執行—— 執行的生命週期及方法

    這篇部落格介紹執行緒的生命週期。   執行緒是一個動態執行的過程,它也有從建立到死亡的過程。 執行緒的幾種狀態 在 Thread 類中,有一個列舉內部類: 上面的資訊以圖片表示如下:   第一張圖:  第二張圖:把等待、計時等待、阻塞看成阻塞一個狀態了 1、新建狀態(ne

    JAVA執行

    多執行緒三 執行緒優先順序 使用者執行緒與守護執行緒 執行緒同步 執行緒通訊 用到的程式碼後面會新增上去,如果急需要的話,評論留下郵箱 執行緒優先順序 (1)每個執行緒都有優先順序,優先順序越高,獲

    Java執行執行其他知識簡要介紹

    一、執行緒組 [java]  view plain  copy /**   * A thread gr

    Java執行:Synchronized

    多執行緒安全 髒讀:多個執行緒對同一個物件的例項變數進行修改後訪問,導致讀到的資料是被修改過的。 例項 ThreadDomain16類 public class ThreadDomain16 { private int num = 0; public void addNum(String u

    Java執行:volatile

    volatile volatile是一種輕量同步機制。請看例子 MyThread25類 public class MyThread25 extends Thread{ private boolean isRunning = true; public boolean isRunning()

    執行:Lock互斥鎖RLock 遞迴鎖Semaphore訊號量Event事件Condition條件Timer定時器queue佇列

    目錄 一、鎖 1)同步鎖 2)死鎖與遞迴鎖 二、訊號量 三、事件 四、條件 五、定時器 六、執行緒佇列 一、鎖 1)同步鎖 #同步鎖的引用 from threading import Thread,Lock import os,time def wor

    Python執行

    引言  在前面的章節我們介紹了使用執行緒和不使使用執行緒的對比例項,並且引入了鎖的概念,這節課我們來了解一下更高階的threading模組。 threading  在threading模組中不