多线程之间的同步控制


问题:


同时运行的几个线程需要共享一个数据,并且要考虑到彼此的状态和动作。


例如,当一个线程对共享的数据进行操作时,在没有完成相关操作之前,不允许其他线程打断它,否则会破坏数据的完整性。也就是说,被多个线程共享的数据在同一时刻只允许一个线程处于操作之中。

 

实现原理:


    为了保证线程安全,使用“锁旗标”;

当线程A获得了一个对象的锁旗标后,线程B若也想获得该对象的锁旗标,就必须等待线程A完成规定的操作并释放出锁旗标后,才能获得该对象的锁旗标,并执行线程B中的操作。



代码实现:


public class ProducerAndConsumer {

	/**
	 * 假定开始售票处并没有票,一个线程往里存票,另一个线程则往外卖票。
	 * 新建一个票类对象,让存票和售票线程都访问它。
	 * 两个线程共享同一个数据对象来实现对同一份数据的操作
	 */
	public static void main(String[] args) {
		Tickets t=new Tickets(10); //新建一个票类对象,总票数作为参数
		new Producer(t).start(); //以票类对象为参数创建存票线程对象,并启动
		new Consumer(t).start();//以同一个票类对象为参数创建售票线程,并启动

	}

}

//票类
class Tickets{
	int number=0; //票号
	int size;	//总票数
	boolean available=false; //表示目前是否有票可售
	public Tickets(int size){this.size=size;}//构造函数,传入总票数参数
}

//存票线程
class Producer extends Thread{
	Tickets t=null;
	public Producer(Tickets t){this.t=t;}//构造函数:以一个票类为参数
	@Override
	public void run() {
		while(t.number<t.size){//限制循环条件为存票序号小于总票数
			synchronized(t){//申请对象t的锁旗标
				System.out.println("Producer puts ticket "+(++t.number));
				t.available=true;//可以买票
			}//自动释放锁旗标
			
		}
	}
}

//售票线程
class Consumer extends Thread{
	Tickets t=null;
	int i=0;
	public Consumer(Tickets t){//构造函数:以一个票类对象为参数
		this.t=t;
	}
	public void run(){
		
		synchronized(t){
			while(i<t.size){ //循环条件为售票序号小于总票数
				if(t.available==true && i<=t.number){ //有票可售且小于目前票序号
					System.out.println("consumer buys ticket "+(++i));
				}
				if(i==t.number){//当票已售到当前序号,则不可售
					t.available=false;
				}
			}
		}
		
	}
}


       一个对象的锁旗标只有一个,所以利用对一个对象锁旗标的争夺,可以实现不同线程的互斥效果。当一个线程获得锁旗标后,需要改锁旗标的其他线程只能处于等待状态。


      另外, 也可以将此关键字加在方法上:


//取票方法
	public synchronized void sell(){
		if(!available){ //如果没有存票,则售票线程等待
			try{
				wait();
			}
			catch(Exception e){
				
			}
			System.out.println("consumer buys ticket "+(number));
			available=false;
			notify();//售票唤醒存票线程开始存票
			if(number==size){
				number=size+1;//在售完最后一张票后,设置一个结束标志
			}//number>size表示售票结束
		}
	}







上一篇:云计算怎么又火了


下一篇:几款主流的App统计工具解析:友盟、Talking Data、openinstall