1. 程式人生 > >多執行緒(四)執行緒的同步之執行緒安全問題

多執行緒(四)執行緒的同步之執行緒安全問題

關於執行緒安全問題,有一個經典的問題:銀行取錢的問題。銀行取錢的基本流程可以分為如下幾個步驟:

1、使用者輸入賬號、密碼,系統判斷使用者的賬戶、密碼是否匹配;

2、使用者輸入取款金額;

3、系統判斷賬戶餘額是否大於取款金額;

4、如果餘額大於取款金額,取款成功;如果餘額小於取款金額,則取款失敗。

初步看上去,這個流程確實就我們日常生活中經常見到的,沒有任何問題。但是如果將這個流程放到多執行緒併發的場景下,就有可能出現問題。注意,是有可能,並不是一定。

下面,我們按照上面的流程去編寫取款程式,而且我們只是使用2條執行緒來模擬取錢操作,模擬兩人使用同一賬戶併發取錢問題。當然,我們不管檢查賬戶和密碼的操作,僅僅模擬後面3步操作。

package gblw.first;

public class Account {
	//封裝賬號編碼、賬號餘額兩個屬性
	private String accountNo;
	private double balance;
	
	public Account(String accountNo,double balance){
		this.accountNo=accountNo;
		this.balance=balance;
	}

	public String getAccountNo() {
		return accountNo;
	}

	public void setAccountNo(String accountNo) {
		this.accountNo = accountNo;
	}

	public double getBalance() {
		return balance;
	}

	public void setBalance(double balance) {
		this.balance = balance;
	}
	
	//下面兩個方法根據accountNo來計算Account的hashCode和判斷equals
	public int hashCode(){
		return accountNo.hashCode();
	}
	
	public boolean equals(Object obj){
		if(obj!=null&&obj.getClass()==Account.class){
			Account target=(Account) obj;
			return target.getAccountNo().equals(accountNo);
		}
		return false;
	}
}

package gblw.first;

public class DrawThread extends Thread{
	//模擬使用者賬戶
	private Account account;
	
	//當前取錢先吃所希望取的錢數
	private double drawAmount;

	public DrawThread(String name,Account account, double drawAmount) {
		super(name);
		this.account = account;
		this.drawAmount = drawAmount;
	}
	//當多條執行緒修改同一個共享資料時,將涉及資料安全問題
	public void run(){
		//賬戶餘額大於取錢數目
		if(account.getBalance()>=drawAmount){
			//吐出鈔票
			System.out.println(getName()+"取錢成功!吐出鈔票:"+drawAmount);
			try {
				Thread.sleep(1);
			} catch (Exception e) {
				e.printStackTrace();
			}
			//修改餘額
			account.setBalance(account.getBalance()-drawAmount);
			System.out.println("\t餘額為:"+account.getBalance());
		}else{
			System.out.println(getName()+"取錢失敗!餘額不足!");
		}
	}	
}

package gblw.first;

public class TestDraw {
	public static void main(String[] args) throws InterruptedException {
		//建立一個賬戶
		Account account=new Account("1234567", 1000);
		//模擬兩個執行緒對同一個賬戶取錢
		new DrawThread("甲", account, 800).start();
		new DrawThread("乙", account, 800).start();
	}
}

執行後的結果如下:

乙取錢成功!吐出鈔票:800.0
甲取錢成功!吐出鈔票:800.0
餘額為:200.0
餘額為:-600.0

竟然餘額為負數,這個肯定是銀行不能接受的,這就是多執行緒高併發情況下引發的執行緒安全問題。


相關推薦

Java 執行—— 單例模式

這篇部落格介紹執行緒安全的應用——單例模式。 單例模式   單例模式,是一種常用的軟體設計模式。在它的核心結構中只包含一個被稱為單例的特殊類。通過單例模式可以保證系統中,應用該模式的類一個類只有一個例項。即一個類只有一個物件例項。 例項: /** * @author

深入理解執行—— Moniter的實現原理

在深入理解多執行緒(一)——Synchronized的實現原理中介紹過關於Synchronize的實現原理,無論是同步方法還是同步程式碼塊,無論是ACC_SYNCHRONIZED還是monitorenter、monitorexit都是基於Monitor實現的,那麼這篇來介紹下什麼是Monitor。

深入理解Java執行

關於java多執行緒的概念以及基本用法:java多執行緒基礎 4,Lock的使用 ReentrantLook類的使用 ReentrantReadWriteLock類的使用 4.1,ReentrantLook類的使用 新建MySe

Java執行java中的Sleep方法

點我跳過黑哥的卑鄙廣告行為,進入正文。 Java多執行緒系列更新中~   正式篇: Java多執行緒(一) 什麼是執行緒 Java多執行緒(二)關於多執行緒的CPU密集型和IO密集型這件事 Java多執行緒(三)如何建立執行緒 Java多執行緒(四)java中的Sleep方法  

執行lock和Condition

lock類似於synchronized,拓展讀寫鎖,讀鎖之間不互斥,寫鎖之間互斥 Condition類似於執行緒技術中的wait和notify 使用lock和Condition能實現更多的特性   設計三個執行緒,第一個執行緒迴圈1次,第二個執行緒迴圈2次,第三個執行緒

2.1.2.4Java執行執行

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

JAVA基礎24-執行【讀寫鎖,阻塞佇列,執行池】

一、讀寫鎖   使用步驟 二、阻塞佇列 (BlockingQueue) 提供執行緒安全的佇列訪問方式; 當阻塞佇列進行插入資料時,若佇列滿,則執行緒阻塞,直到佇列非滿的時候 當阻塞佇列取資料時,若佇列為空,則執行緒阻塞直到佇列非空時候。

程序與執行--NPTL(轉)

Native POSIX Thread Library(NPTL)是一個能夠使使用POSIX Threads編寫的程式在Linux核心上更有效地執行的軟體。測試表明,NPTL能夠成功地在IA-32平臺上在兩秒種內生成100,000個執行緒;相應的沒有NPTL的核心將耗費15分鐘左右。歷史在Linux核心2.6

理解執行--原子量和原子操作

原子量 互斥量可以對於共享變數的訪問進行加鎖,可以保證對臨界區的互斥訪問,但加鎖總是繁瑣的,所以提供了更簡單的共享變數保護訪問的操作,原子量和原子操作。 原子量的構造 原子量包含在#include 中,對於基本型別,我們可以這樣定義原子變數 std::atomic_b

Java執行執行

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

執行執行——執行排程

四、執行緒排程   執行緒排程管理器負責執行緒排隊和CPU線上程間的分配,並按執行緒排程演算法進行排程。當執行緒排程管理器選中某個執行緒時,該執行緒獲得 CPU資源進人執行狀態。   執行緒排程是搶佔式排程,即如果在當前執行緒執行過程中個更高優先順序的執行緒

執行】程式猿進階執行—— 執行同步

一、前言       在上一篇部落格,小編向大家介紹了執行緒的狀態,算是進一步拉開了多執行緒的面試,在這篇部落格中,小編向大家介紹一下多執行緒中常見問題有執行緒同步和執行緒通訊,這篇部落格中小編向大家

執行執行同步執行安全問題

關於執行緒安全問題,有一個經典的問題:銀行取錢的問題。銀行取錢的基本流程可以分為如下幾個步驟: 1、使用者輸入賬號、密碼,系統判斷使用者的賬戶、密碼是否匹配; 2、使用者輸入取款金額; 3、系統判斷賬

執行執行同步同步方法

與同步程式碼塊對應的,Java的多執行緒安全支援還提供了同步方法,同步方法就是使用synchronized關鍵字來修飾某個方法,該方法稱為同步方法。對於同步方法而言,無須顯式指定同步監視器,同步方法的

Java總結篇系列:Java執行

多個執行緒同步執行ping ip示例package com.ebao.pojo;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import j

網路程式設計基礎【day10】:我是一個執行

本節內容 1、第一回 初生牛犢 2、第二回 漸入佳境 3、第三回 虎口脫險 4、第四回 江湖再見 第一回 初生牛犢 我是一個執行緒,我一出生就被編了個號:0x3704,然後被領到一個昏暗的屋子裡,在這裡我發現了很多和我一模一樣的同伴。 我身邊的同伴0x6900 待的時間比較長,他帶著滄桑的口氣對

執行

import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * 生產者和

Windows執行執行同步與互斥問題

執行緒同步與互斥的測試函式如下所示: #include <stdio.h> #include <process.h> #include <Windows.h> #define THREAD_NUM 10 unsigned long g_nNum

linux網路程式設計posix 執行:posix 條件變數與互斥鎖 示例生產者--消費者問題

#include <unistd.h>#include <sys/types.h>#include <pthread.h>#include <semaphore.h>#include <stdlib.h>#include <stdio.h>

Windows執行使用事件機制解決執行同步問題

事件相關函式: 1.建立事件:CreateEvent HANDLE CreateEvent ( LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState,