线程同步:
?一、线程同步:
??线程的同步,就是要保证线程在执行某个计算时,需要保证相关的数据在这个计算过程中只能被一个线程访问,即保证访问数据的原子性---就像一个坐位,只能同时被一个人(线程)所使用。
?
?二、举例,以在银行取钱为例子:
? ?1.创建账户:
?
package 线程同步; /** * 银行账户对象 * @author Administrator * */ public class Account { private int total=0; //构造有指定金额的银行账户 public Account(int save){ this.total = save; } public String toString(){ return "账户余额:"+total; } //取钱的 private void disSave(int count){ try{ Thread.sleep(1000); }catch(Exception ed){ } total=total-count; } //从账户上提取现金的调用方法 public int getCash(int count){ //金额不足 if (total<count) { return -1; } //从账户上减去提取金额 disSave(count); return count; } }
?
?
? 2.取钱线程:
package 线程同步; public class GetCashThread extends Thread { private Account ac;//操作账户 private String flag;//取钱方式 private int disCount;//取现金额 @Override public void run() { // TODO Auto-generated method stub //super.run(); //在这里取钱 //synchronized (ac) { int cash=ac.getCash(disCount); System.out.println(flag+"取了:"+cash); //} } public GetCashThread(Account ac,String flag,int disCount){ this.ac = ac; this.flag = flag; this.disCount = disCount; } }
??
?
? ?3.Main类:
package 线程同步; public class DriverBank { public static void main(String[] args) { //创建一个账号: Account ac = new Account(5000); //从ATM取 GetCashThread atmGet = new GetCashThread(ac, "ATM取款", 2500); //从柜台取 GetCashThread counterGet = new GetCashThread(ac, "从柜台取款", 2600); //启动取款线程 atmGet.start(); counterGet.start(); //主线程暂停,等到前面两个取款线程完成,打印出账户余额 try { Thread.sleep(3000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(ac); } }
??
?三、运行结果:
? ?
?
? ? ?账户共有5000,可是分别取到2500,2600,余额是-100,这就是线程不同步,所造成的结果.ATM的线程取钱时,柜台取钱进入取钱,此时的ATM的线程还未结算完,导致账户上还是5000,
?
?四、处理
? 解决原理:避免多个线程同时操作某一个对象的数据,就要让多线程操作对象的数据时候有一个先后顺序,一个操作完成另一个线程在操作的。
?
? ? 解决1---使用synchronized关键字
? 这个关键字可以放在一个方法前,表示这个方法同时只能被一个线程访问,或通过锁定某个对象放在代码块前,表示其限定的代码块只能同时被一个线程防问。
?代码改善:
synchronized (ac) { int cash=ac.getCash(disCount); System.out.println(flag+"取了:"+cash); }
?运行结果:
?
?
?
?解决2--使用java.util.concurrent包
?这个包中有许多对并发编程有良好支持的类,其中新增了一个java.util.concurrent.locks.Lock接口,这是一个“锁”对象的接口,它的多个实现的子类可用来支持线程同步时灵活的锁机制
?代码改善:
package 线程同步;
import java.util.concurrent.locks.*; import java.util.concurrent.locks.ReentrantLock; public class GetCashThread extends Thread { private Account ac;//操作账户 private String flag;//取钱方式 private int disCount;//取现金额 //定义一个同步锁 private static Lock myLock = new ReentrantLock(); @Override public void run() { // TODO Auto-generated method stub //super.run(); //在这里取钱 try{ myLock.lock();// 仅有一个线程可同时执行此段代码 int cash=ac.getCash(disCount); System.out.println(flag+"取了:"+cash); }finally{ myLock.unlock(); } } public GetCashThread(Account ac,String flag,int disCount){ this.ac = ac; this.flag = flag; this.disCount = disCount; } }
?运行结果:
?
?
?
五、总结.
? 避免多线程同时操作某一对象的数据,要给线程加上执行顺序.
?
原文:http://cb123456.iteye.com/blog/2215626