java线程间通信

在前面我们将了很多关于同步的问题,然而在现实中,需要线程之间的协作。比如说最经典的生产者-消费者模型:当队列满时,生产者需要等待队列有空间才能继续往里面放入商品,而在等待的期间内,生产者必须释放对临界资源(即队列)的占用权。因为生产者如果不释放对临界资源的占用权,那么消费者就无法消费队列中的商品,就不会让队列有空间,那么生产者就会一直无限等待下去。因此,一般情况下,当队列满时,会让生产者交出对临界资源的占用权,并进入挂起状态。然后等待消费者消费了商品,然后消费者通知生产者队列有空间了。同样地,当队列空时,消费者也必须等待,等待生产者通知它队列中有商品了。这种互相通信的过程就是线程间的协作

Java中线程通信协作的最常见的两种方式:

  一.syncrhoized加锁的线程的Object类的wait()/notify()/notifyAll()

  二.ReentrantLock类加锁的线程的Condition类的await()/signal()/signalAll()

本篇先说第一种方式。

wait()、notify()和notifyAll()是Object类中的方法:

      1)wait()、notify()和notifyAll()方法是本地方法,并且为final方法,无法被重写。

  2)调用某个对象的wait()方法能让当前线程阻塞,并且当前线程必须拥有此对象的monitor(即锁)

  3)调用某个对象的notify()方法能够唤醒一个正在等待这个对象的monitor的线程,如果有多个线程都在等待这个对象的monitor,则只能唤醒其中一个线程

  4)调用notifyAll()方法能够唤醒所有正在等待这个对象的monitor的线程

       wait与notify实现线程间的通信实例:

面试题:子线程循环10次,接着主线程循环100,接着又回到子线程循环10次,接着再回到主线程又循环100,如此循环50次,请写出程序:

package ThreadDemo;
public class ThreadTest {
	private static boolean bShouldMain = false;//这里相当于定义了控制该谁执行的一个信号灯
	public static void main(String[] args) {
		//因为用到了匿名内部类,内部类访问的局部变量需要用final修饰
		final Business business = new Business();
		new Thread(
				new Runnable(){
					public void run() {
						for(int i=1;i<=50;i++){
							//这里使用类的字节码对象作为锁进行同步,但是当需要对同步进行分组时就不科学了
							business.sub(i);
						}
					}
				}
		).start();
 
		//main方法本身是一个线程,这里是主线程的运行代码
		for(int i=1;i<=50;i++){
			business.main(i);
		}
	}
}
 
class Business {
	private boolean bShouldSub = true;//最开始该子线程走
	public synchronized void sub(int i){
		while(!bShouldSub){//用while而不是if线程醒来还会再次进行判断,防止代码被伪唤醒,代码更健壮。还可以防止生产者消费者问题
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		for(int j=1;j<=10;j++){
			System.out.println("sub thread sequence of "+j+", loop of "+i);
		}
		bShouldSub = false;
		this.notify();
	}
	public synchronized void main(int i){
		while(bShouldSub){
			try {
				this.wait();//这里的锁是this
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		for(int j=1;j<=100;j++){
			System.out.println("main thread sequence of "+j+", loop of "+i);
		}
		bShouldSub = true;
		this.notify();
	}
}

经验:

  1. 要用到共同数据(包括同步锁)或共同算法的若干方法应该归在同一个类身上,这种设计正好体现了高类聚和程序的健壮性
  2. 锁是上在要操作的资源的类的内部方法中,而不是线程代码中!好处是以后该类交给任何线程自然就同步了,而不需要考虑互斥同步的问题。
  3. Eclipse中将运行结果保存至文件的操作:Run as-->Run Configuration-->Common-->File处打钩然后选择一个文件

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值