线程同步

线程同步:

 一、线程同步:

  线程的同步,就是要保证线程在执行某个计算时,需要保证相关的数据在这个计算过程中只能被一个线程访问,即保证访问数据的原子性---就像一个坐位,只能同时被一个人(线程)所使用。

 

 二、举例,以在银行取钱为例子:

   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;
		
	}
	
}

 运行结果:

 
 
 

五、总结.

  避免多线程同时操作某一对象的数据,要给线程加上执行顺序.

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值