并发集合(八)使用原子变量
声明:本文是《 Java 7 Concurrency Cookbook 》的第一章, 作者: Javier Fernández González 译者:郑玉婷 校对:方腾飞 在Java 1.5中就引入了原子变量,它提供对单个变量的原子操作。当你在操作一个普通变量时,你在Java实现的每个操作,在程序编译时会
声明:本文是《 Java 7 Concurrency Cookbook 》的第一章, 作者: Javier Fernández González 译者:郑玉婷 校对:方腾飞
在Java 1.5中就引入了原子变量,它提供对单个变量的原子操作。当你在操作一个普通变量时,你在Java实现的每个操作,在程序编译时会被转换成几个机器能读懂的指令。例如,当你分配一个值给变量,在Java你只使用了一个指令,但是当你编译这个程序时,这个指令就被转换成多个JVM 语言指令。这样子的话当你在操作多个线程且共享一个变量时,就会导致数据不一致的错误。
为了避免这样的问题,Java引入了原子变量。当一个线程正在操作一个原子变量时,即使其他线程也想要操作这个变量,类的实现中含有一个检查那步骤操作是否完成的机制。 基本上,操作获取变量的值,改变本地变量值,然后尝试以新值代替旧值。如果旧值还是一样,那么就改变它。如果不一样,方法再次开始操作。这个操作称为 Compare and Set(校对注:简称CAS,比较并交换的意思)。
原子变量不使用任何锁或者其他同步机制来保护它们的值的访问。他们的全部操作都是基于CAS操作。它保证几个线程可以同时操作一个原子对象也不会出现数据不一致的错误,并且它的性能比使用受同步机制保护的正常变量要好。
在这个指南,你将学习怎样使用原子变量实现一个银行账户和2个不同的任务:一个存钱到账户和另一个从账户提取钱。在例子的实现中,你将使用 AtomicLong 类。
准备
指南中的例子是使用Eclipse IDE 来实现的。如果你使用Eclipse 或者其他的IDE,例如NetBeans, 打开并创建一个新的java项目。
怎么做呢…
按照这些步骤来实现下面的例子:
[ code language='java']
//1. 创建一个类,名为 Account,来模拟银行账号。
public class Account {
//2. 声明一个私有 AtomicLong 属性,名为 balance,用来储存账号的余额。
private AtomicLong balance;
//3. 实现类的构造函数,初始化它的属性值。
public Account(){
balance=new AtomicLong();
}
//4. 实现一个方法,名为 getBalance(),用来返回余额属性值。
public long getBalance() {
return balance.get();
}
//5. 实现一个方法,名为 setBalance(),用来设置余额属性值。
public void setBalance(long balance) {
this.balance.set(balance);
}
//6. 实现一个方法,名为 addAmount(),来增加余额属性值。
public void addAmount(long amount) {
this.balance.getAndAdd(amount);
}
//7. 实现一个方法,名为 substractAmount() 来减少余额属性值。
public void subtractAmount(long amount) {
this.balance.getAndAdd(-amount);
}
//8. 创建一个类,名为 并一定实现 Runnable 接口。这个类会模拟公司付款。
public class Company implements Runnable {
//9. 声明一个私有 Account 属性,名为 account。
private Account account;
//10. 实现类的构造函数,初始化它的属性值。
public Company(Account account) {
this.account=account;
}
//11. 实现任务的 run() 方法。 使用 account 的 addAmount()方法来让它的余额做10次的递增,递增额为1000。
@Override
public void run() {
for (int i=0; i
account.addAmount(1000);
}
}
//12. 创建一个类,名为 Bank,并一定实现 Runnable 接口。这个类会模拟从一个账号提款。
public class Bank implements Runnable {
//13. 声明一个私有 Account 属性,名为 account。
private Account account;
//14. 实现类的构造函数,初始化它的属性值。
public Bank(Account account) {
this.account=account;
}
//15. 实现任务的 run() 方法。使用 account 的 subtractAmount() 方法来让它的余额做10次的递减,递减额为1000。
@Override
public void run() {
for (int i=0; i
account.subtractAmount(1000);
}
}
//16. 创建例子的主类通过创建一个类,名为 Main 并添加 main()方法。
public class Main {
public static void main(String[] args) {
//17. 创建一个 Account 对象,设置它的余额为 1000。
Account account=new Account();
account.setBalance(1000);
//18. 创建新的 Company 任务和一个线程运行它。
Company company=new Company(account);
Thread companyThread=new Thread(company);
// 创建一个新的 Bank t任务和一个线程运行它。
Bank bank=new Bank(account);
Thread bankThread=new Thread(bank);
//19. 在操控台写上账号的初始余额。
System.out.printf(“Account : Initial Balance: %d\n”,account. getBalance());
//20. 开始线程。
companyThread.start();
bankThread.start();
//21. 使用 join() 方法等待线程的完结并把账号最终余额写入操控台。
try {
companyThread.join();
bankThread.join();
System.out.printf(“Account : Final Balance: %d\n”,account. getBalance());
} catch (InterruptedException e) {
e.printStackTrace();
}
[/code]
它是怎么工作的...
这个例子的关键是 Account 类。在这个类,我们声明了一个 AtomicLong 属性,名为 balance,用来储存账户余额,然后我们使用 AtomicLong 类提供的方法实现了操作余额的方法。为了实现 getBalance() 方法,返回余额的属性值,你要使用 AtomicLong 类的 get() 方法。为了实现 setBalance() 方法,设立余额值,你要使用 AtomicLong 类的 set() 方法。为了实现 addAmount()方法,为余额值加上收入,你要使用 AtomicLong 类的getAndAdd() 方法,用特定的参数值增加它并返回值。最后,为了实现 subtractAmount() 方法,减少余额值,你也要使用 getAndAdd() 方法。
接着,你实现了2个不同的任务:
Company 类模拟了一个公司,增加余额值。这个类的每次任务会做10次的递增,递增值为1000。
Bank 类模拟了一个银行,银行作为账号的拥有者而收取费用。这个类的每次任务会做10次的递减,递减值为1000。
在 Main 类,你创建了一个有1000余额的 Account 对象。然后,你运行一个银行任务和一个公司任务,所以最终的账号余额一定是等同于初始余额。
当你运行程序,你可以发现你的最终余额和你的初始值一样。以下的截图是例子的运行结果的输出:
更多...
记得我们之前提到的,Java还有其他的原子类哦。例如:AtomicBoolean, AtomicInteger, 和 AtomicReference。
参见
第二章,基本线程同步:同步一个方法
原文地址:并发集合(八)使用原子变量, 感谢原作者分享。

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

在如今雲端儲存已成為我們日常生活和工作中不可或缺的一部分。百度網盤作為國內領先的雲端儲存服務之一,憑藉其強大的儲存功能、高效的傳輸速度以及便捷的操作體驗,贏得了廣大用戶的青睞。而且無論你是想要備份重要文件、分享資料,還是在線上觀看影片、聽取音樂,百度網盤都能滿足你的需求。但很多用戶可能對百度網盤app的具體使用方法還不了解,那麼這篇教學就將為大家詳細介紹百度網盤app如何使用,還有疑惑的用戶們就快來跟著本文詳細了解一下吧!百度雲網盤怎麼用:一、安裝首先,下載並安裝百度雲軟體時,請選擇自訂安裝選

網易郵箱,作為中國網友廣泛使用的一種電子郵箱,一直以來以其穩定、高效的服務贏得了用戶的信賴。而網易信箱大師,則是專為手機使用者打造的信箱軟體,它大大簡化了郵件的收發流程,讓我們的郵件處理變得更加便利。那麼網易信箱大師該如何使用,具體又有哪些功能呢,下文中本站小編將為大家帶來詳細的內容介紹,希望能幫助到大家!首先,您可以在手機應用程式商店搜尋並下載網易信箱大師應用程式。在應用寶或百度手機助手中搜尋“網易郵箱大師”,然後按照提示進行安裝即可。下載安裝完成後,我們打開網易郵箱帳號並進行登錄,登入介面如下圖所示

MetaMask(中文也叫小狐狸錢包)是一款免費的、廣受好評的加密錢包軟體。目前,BTCC已支援綁定MetaMask錢包,綁定後可使用MetaMask錢包進行快速登錄,儲值、買幣等,且首次綁定還可獲得20USDT體驗金。在BTCCMetaMask錢包教學中,我們將詳細介紹如何註冊和使用MetaMask,以及如何在BTCC綁定並使用小狐狸錢包。 MetaMask錢包是什麼? MetaMask小狐狸錢包擁有超過3,000萬用戶,是當今最受歡迎的加密貨幣錢包之一。它可免費使用,可作為擴充功能安裝在網絡

小米汽車軟體提供遠端車控功能,讓使用者可以透過手機或電腦遠端控制車輛,例如開關車輛的門窗、啟動引擎、控制車輛的空調和音響等,下文就是這個軟體的使用及內容,一起了解下吧。小米汽車app功能及使用方法大全1、小米汽車app在3月25日上線蘋果AppStore,現在安卓手機的應用商店中也可以下載了;購車:了解小米汽車核心亮點和技術參數,可預約試駕、配置訂購您的小米汽車,支援線上處理提車待辦事項。 3.社群:了解小米汽車品牌資訊,交流用車體驗,分享精彩車生活;4、車控:手機就是遙控器,遠端控制,即時安防,輕

並發和協程在GoAPI設計中可用於:高效能處理:同時處理多個請求以提高效能。非同步處理:使用協程非同步處理任務(例如傳送電子郵件),釋放主執行緒。流處理:使用協程高效處理資料流(例如資料庫讀取)。

使用Java函數的並發和多執行緒技術可以提升應用程式效能,包括以下步驟:理解並發和多執行緒概念。利用Java的並發和多執行緒函式庫,如ExecutorService和Callable。實作多執行緒矩陣乘法等案例,大幅縮短執行時間。享受並發和多執行緒帶來的應用程式響應速度提升和處理效率優化等優勢。

Go語言是一種簡單、有效率、並發性強的程式語言,它是由Google開發的開源語言。在Go語言中,空格的使用是非常重要的,它能夠提高程式碼的可讀性和易於維護性。本文將介紹如何正確地在Go語言中使用空格,並提供具體的程式碼範例。為什麼需要正確使用空格在程式設計過程中,空格的使用對於程式碼的可讀性和美觀性非常重要。恰當地使用空格可以讓程式碼更加清晰、易讀,從而減

事務確保資料庫資料完整性,包括原子性、一致性、隔離性和持久性。 JDBC使用Connection介面提供交易控制(setAutoCommit、commit、rollback)。並發控制機制協調並發操作,使用鎖或樂觀/悲觀並發控制來實現事務隔離性,以防止資料不一致。
