一、原子变量
原子变量是Java 5 开始引入的,他提供了单个变量上的原子操作。
当一个线程在对原子变量操作时,如果其他线程也试图对对同一原子变量执行操作,原子变量的实现类提供了一套机制来检查操作是否在一步内完成。
这个操作下 获取变量值,然后在本地改变变量的值,然后试图用这个改变的值去替换之前的值。如果之前的值没有被其他线程改变,就可以执行这个替换操作。否则,方法将再执行这个操作。这种操作称为CAS原子操作(Compare and set)
原子变量不使用锁或其他同步机制来保护对其值的并发访问。所有的操作都是基于CAS原子操作的,并且性能优于使用同步机制保护的普通变量。
二、模拟账户
package concurrencycollection; import java.util.concurrent.atomic.AtomicLong; public class Account { private AtomicLong balance;// 账户余额 public Account() { // TODO Auto-generated constructor stub balance = new AtomicLong(); } public long getBalance() { return balance.get(); } public void setBalance(long amount) { this.balance.set(amount);; } public void addBalance(long amount) { // TODO Auto-generated method stub this.balance.getAndAdd(amount); } public void substractAmount(long amount) { this.balance.getAndAdd(-amount); } }
package concurrencycollection; public class Company implements Runnable { private Account account; public Company(Account account) { // TODO Auto-generated constructor stub this.account = account; } @Override public void run() { // TODO Auto-generated method stub for (int i = 0; i < 10; i++) { account.addBalance(1000); } } }
package concurrencycollection; public class Bank implements Runnable { private Account account; public Bank(Account account) { // TODO Auto-generated constructor stub this.account = account; } @Override public void run() { // TODO Auto-generated method stub for (int i = 0; i < 10; i++) { account.substractAmount(1000); } } }
package concurrencycollection; public class Main2 { public static void main(String[] args) { // TODO Auto-generated method stub Account account = new Account(); account.setBalance(1000); Company company = new Company(account); Bank bank = new Bank(account); Thread threadCompany = new Thread(company); Thread threadBank = new Thread(bank); System.out.println("Initial Balance is " + account.getBalance()); threadCompany.start(); threadBank.start(); try { threadCompany.join(); threadBank.join(); System.out.println("Account : Final Balance : " + account.getBalance()); } catch (InterruptedException e) { e.printStackTrace(); } } }