线程间通信

之前的售票程序或者银行取钱例子中,所有线程执行的代码都是一样的。
线程间通信:A线程往里存,B线程往外取。
AB线程的动作不一致,也就需要有两个run方法。两个run方法就要存在两个线程当中。什么时候可以取,什么时候可以存,这就需要线程之间的通信。

例子:一个写入线程负责写,读取线程负责读,两者操作的是同一个资源,但是操作的动作是不同的。这时就要进行线程间通信。

package fighting;

public class ThreadCommunication {

	/**
	 * 线程间通讯:解决安全问题(要用同一个锁)
	 * 其实就是多个线程在操作同一个资源,但是操作的动作不同。这样就需要通讯。
	 * 
	 * 同步以后也会发生一种情况:
	 * 就是输入线程往里存了一个,输出线程可能会执行了多次,取了多次,
	 * 这样输出线程就会取到多次相同的值。这需要等待唤醒机制来解决。
	 * 等待唤醒机制:就是需要一个资源的flag。
	 * 
	 * wait()和notify(),notifyAll()
	 * 这几个方法都是用在同步中,要对持有监视器(也就是锁)的线程操作。
	 * 
	 * 为什么线程用到的方法wait()和notify(),notifyAll()会定义在Oject类中,而不是定义在Thread类中?
	 * 因为这些方法在操作同步的线程时,都必须要标识它们所操作线程持有的锁。
	 * 只有同一个锁上的被等待线程,可以被同一个锁上nofify唤醒。
	 * 不可以对不同锁中的线程唤醒。
	 * 也就是说,等待和唤醒必须是同一个锁。
	 * 而锁可以使任意对象,所以可以被任意对象调用的方法要定义在Oject类中。
	 *
	 */
	public static void main(String[] args) {
		Resource r = new Resource();
		
		InputThread in = new InputThread(r);
		OutputThread out  = new OutputThread(r);
		
		new Thread(in).start();
		new Thread(out).start();

	}

}
//线程要操作的资源
class Resource{
	String name;
	String sex;
	boolean flag = false;//等待唤醒机制的标志位
}
//输入的线程
class InputThread implements Runnable{

	private Resource r;
	InputThread(Resource r){
		this.r=r;
	}
	public void run() {//同步synchronize写在run方法,就变成了单线程了,一个线程进来,其他线程就进不来了
		boolean b=true;
		int i=0;
		while(true){
			/**
			 * 这里同步锁用了r,是因为InputThread和OutputThread两个线程操作的都是一个r。
			 * 这里也可以用InputThread.class或OutputThread.class或Resource.class,
			 * 只要在内不能中是唯一的就可以,但是这样显得牵强。
			 */
			synchronized (r) {
				if(r.flag){//flag为True,说明已经有资源,不用再存,线程等待
					try {
						r.wait();//知识点:等待的线程存在内存线程池中,notify唤醒的都是线程池中的线程。
						         //注意:wait和notify方法必须标明是哪个锁,而且这个锁要和同步的锁是一个才可以。
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				if(b){
					r.name="张三"+(i++);
					r.sex="男";
					b=false;
				}else{
					r.name="李四"+(i++);
					r.sex="女";
					b=true;
				}
				r.flag=true;
				r.notify();//唤醒等待的一个线程。还有一个方法notifyAll,唤醒所有等待的线程
			}
		}
	}
	
}
//取走的线程
class OutputThread implements Runnable{
	private Resource r;
	OutputThread(Resource r){
		this.r=r;
	}
	public void run() {
		while(true){
			synchronized (r) {
				if(!r.flag){//flag为false,说明没有资源,不能取,线程等待
					try {
						r.wait();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				System.out.println(r.name+"..."+r.sex);
				r.flag=false;
				r.notify();
			}
		}
		
	}
	
}

代码优化:把资源类Resource的成员私有化。

package fighting;

public class ThreadCommunication {

	/**
     * 代码优化:把资源私有化
	 */
	public static void main(String[] args) {
		Resource r = new Resource();
		
		InputThread in = new InputThread(r);
		OutputThread out  = new OutputThread(r);
		
		new Thread(in).start();
		new Thread(out).start();

	}

}
//线程要操作的资源
class Resource{
	private String name;
	private String sex;
	private boolean flag = false;//等待唤醒机制的标志位
	public synchronized void set(String name,String sex){
		if(flag){
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		this.name=name;
		//--->如果线程在执行完上一句,在这里被其他线程抢走了执行权,则这里会出现安全问题,所以这个方法需要同步
		this.sex=sex;
		flag=true;
		this.notify();//有资源了,将其他线程唤醒,通知可以取资源了
	}
	public synchronized void out(){
		if(!flag){
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		System.out.println(name+"..."+sex);
		flag=false;
		this.notify();//这句唤醒要写在资源里面,如果线程里面,
		              //就会报错IllegalMonitorStateException(意思是当前线程不是此对象监视器的所有者)。
	}
}
//输入的线程
class InputThread implements Runnable{

	private Resource r;
	InputThread(Resource r){
		this.r=r;
	}
	public void run() {//同步synchronize写在run方法,就变成了单线程了,一个线程进来,其他线程就进不来了
		boolean b=true;
		int i=0;
		while(true){
				if(b){
					r.set("张三"+(i++), "男");
					b=false;
				}else{
					r.set("李四"+(i++), "女");
					b=true;
				}
//				r.notify();//这句唤醒如果这里,就会报错IllegalMonitorStateException(意思是当前线程不是此对象监视器的所有者),
				           //因为同步是在资源类的方法上实现的,程序执行到这的时候,已经从同步方法里出来了。
				           //当前线程是InputThread这个线程,同步锁的所有者是Resource,
		}
	}
	
}
//取走的线程
class OutputThread implements Runnable{
	private Resource r;
	OutputThread(Resource r){
		this.r=r;
	}
	public void run() {
		while(true){
				r.out();
//				r.notify();
		}
		
	}
	
}



 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值