声明:本文是《 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。
参见
第二章,基本线程同步:同步一个方法
原文地址:并发集合(八)使用原子变量, 感谢原作者分享。

如何有效监控MySQL性能?使用mysqladmin、SHOWGLOBALSTATUS、PerconaMonitoringandManagement(PMM)和MySQLEnterpriseMonitor等工具。1.使用mysqladmin查看连接数。2.用SHOWGLOBALSTATUS查看查询数。3.PMM提供详细性能数据和图形化界面。4.MySQLEnterpriseMonitor提供丰富的监控功能和报警机制。

MySQL和SQLServer的区别在于:1)MySQL是开源的,适用于Web和嵌入式系统,2)SQLServer是微软的商业产品,适用于企业级应用。两者在存储引擎、性能优化和应用场景上有显着差异,选择时需考虑项目规模和未来扩展性。

在需要高可用性、高级安全性和良好集成性的企业级应用场景下,应选择SQLServer而不是MySQL。1)SQLServer提供企业级功能,如高可用性和高级安全性。2)它与微软生态系统如VisualStudio和PowerBI紧密集成。3)SQLServer在性能优化方面表现出色,支持内存优化表和列存储索引。

mySqlManagesCharacterSetsetSandCollationsyutusututf-8asthEdeFault,允许ConfigurationAtdataBase,table和columnlevels,AndrequiringCarefullageLignmentToavoidMismatches.1)setDefeaultCharactersetTercharactersetEtCollacterSeteTandColletationForAdataBase.2)conformentcollecharactersettersetertersetcollatertersetcollationcollation

MySQL触发器是与表相关联的自动执行的存储过程,用于在特定数据操作时执行一系列操作。1)触发器定义与作用:用于数据校验、日志记录等。2)工作原理:分为BEFORE和AFTER,支持行级触发。3)使用示例:可用于记录薪资变更或更新库存。4)调试技巧:使用SHOWTRIGGERS和SHOWCREATETRIGGER命令。5)性能优化:避免复杂操作,使用索引,管理事务。

在MySQL中创建和管理用户账户的步骤如下:1.创建用户:使用CREATEUSER'newuser'@'localhost'IDENTIFIEDBY'password';2.分配权限:使用GRANTSELECT,INSERT,UPDATEONmydatabase.TO'newuser'@'localhost';3.修正权限错误:使用REVOKEALLPRIVILEGESONmydatabase.FROM'newuser'@'localhost';然后重新分配权限;4.优化权限:使用SHOWGRA

MySQL适合快速开发和中小型应用,Oracle适合大型企业和高可用性需求。1)MySQL开源、易用,适用于Web应用和中小型企业。2)Oracle功能强大,适合大型企业和政府机构。3)MySQL支持多种存储引擎,Oracle提供丰富的企业级功能。

MySQL相比其他关系型数据库的劣势包括:1.性能问题:在处理大规模数据时可能遇到瓶颈,PostgreSQL在复杂查询和大数据处理上表现更优。2.扩展性:水平扩展能力不如GoogleSpanner和AmazonAurora。3.功能限制:在高级功能上不如PostgreSQL和Oracle,某些功能需要更多自定义代码和维护。


热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

禅工作室 13.0.1
功能强大的PHP集成开发环境

DVWA
Damn Vulnerable Web App (DVWA) 是一个PHP/MySQL的Web应用程序,非常容易受到攻击。它的主要目标是成为安全专业人员在合法环境中测试自己的技能和工具的辅助工具,帮助Web开发人员更好地理解保护Web应用程序的过程,并帮助教师/学生在课堂环境中教授/学习Web应用程序安全。DVWA的目标是通过简单直接的界面练习一些最常见的Web漏洞,难度各不相同。请注意,该软件中

mPDF
mPDF是一个PHP库,可以从UTF-8编码的HTML生成PDF文件。原作者Ian Back编写mPDF以从他的网站上“即时”输出PDF文件,并处理不同的语言。与原始脚本如HTML2FPDF相比,它的速度较慢,并且在使用Unicode字体时生成的文件较大,但支持CSS样式等,并进行了大量增强。支持几乎所有语言,包括RTL(阿拉伯语和希伯来语)和CJK(中日韩)。支持嵌套的块级元素(如P、DIV),

SublimeText3 英文版
推荐:为Win版本,支持代码提示!

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