多线程通信( wait(),notify(),notifyAll() )

多线程通信:

线程之间进行通信,协同完成工作。例如一条流水线的上下两个工序,他们必须以规定的速率完成各自的工作,才能保证产品再流水线中顺利的流转。如果下工序过慢,会造成产品再两道工序之间的积压,如果上工序过慢,会造成下工序长时间无事可做。线程之间的通信,可以让整个工作更好的完成。

1、下面一个例子,两个线程去操作同一个存储空间,其中一个线程向存储空间存入数据,另一个线程负责取出数据。用此例子来演示线程之间没有进行通信时的结果

class Storage {
	// 数据存储数组
	private int[] cells = new int[10];
	// inPos表示存入时数组下标,outPos表示取出时数组下标
	private int inPos, outPos;
        // 定义一个put()方法向数组中存入数据
	public void put(int num) {
		cells[inPos] = num;
		System.out.println("在cells[" + inPos + "]中放入数据---" + cells[inPos]);
		inPos++;// 存完元素让位置加1
		if (inPos == cells.length)
			inPos = 0;      // 当inPos为数组长度时,将其置为0
	}
        // 定义一个get()方法从数组中取出数据
	public void get() {
		int data = cells[outPos];
		System.out.println("从celss[" + outPos + "]中取出数据" + data);
		outPos++;            // 取完元素让位置加1
		if (outPos == cells.length)
			outPos = 0;
	}
}

public class Input implements Runnable{		    // 输入线程类
	private Storage st ;
     private int num=0;                           // 定义一个变量num 
	Input(Storage st){                         // 通过构造方法接收一个Storage对象
		this.st = st;
	}
	public void run(){        
		while(true){
			if(num==10){
				break;
			}
			st.put(num++);                   // 将num存入数组,每次存入后num自增
		}
	}
}

class Output implements Runnable{	       //输出线程类
	private Storage st ;
	Output(Storage st){
		this.st = st;
	}
	public void run(){
		while(true){
			st.get();
		}
	}
}

public class Example17 {
	public static void main(String[] args) {
		Storage st = new Storage(); // 创建数据存储类对象
		Input input = new Input(st);	// 创建Input对象传入Storage对象
		Output output = new Output(st); 	// 创建Output对象传入Storage对象
		new Thread(input).start();		// 开启新线程
		new Thread(output).start();		// 开启新线程
	}
}
结果:

在cells[0]中放入数据---0
从celss[0]中取出数据0
在cells[1]中放入数据---1
从celss[1]中取出数据1
在cells[2]中放入数据---2
从celss[2]中取出数据2
在cells[3]中放入数据---3
从celss[3]中取出数据3
从celss[4]中取出数据4
在cells[4]中放入数据---4
从celss[0]中取出数据0
在cells[0]中放入数据---5
从celss[1]中取出数据1
在cells[1]中放入数据---6
从celss[2]中取出数据2
在cells[2]中放入数据---7
从celss[3]中取出数据3
在cells[3]中放入数据---8
从celss[4]中取出数据4
在cells[4]中放入数据---9


2、若想让多个线程之间轮流执行,例如让输入线程输入后,输入线程输出输入的数之后再进行输出,就可以设置多线程通信,来达到目的,如下改进代码所示

详解:再Java中,再Object类中,提供了wait(),notify(),notifyAll()方法用于解决线程间的通信问题。

void wait() :使当前线程放弃同步锁进入等待,直到其他线程进入此同步锁,并调用notify()方法,或notifyAll()方法唤醒该线程为止。

void notify():唤醒此同步锁上等待的第一个调用wait()方法的线程。

void notify():唤醒此同步锁上调用wait()方法的所有线程。

下列改进代码中,首先用synchronized关键字将put()方法和get()方法修饰为同步方法,每个时间点仅有一种操作访问数组,当存入数据时,数组填满,调用同步锁wait()方法使存入数据的线程进入等待状况,让取出数据的线程开始操作,取完之后调用同步锁wait()方法进入等待,之后重复进行。

class Storage {
	private int[] cells = new int[5];   // 数据存储数组
	private int inPos, outPos;            // inPos存入时数组下标,outPos取出时数组下标
	private int count;                      // 存入或者取出数据的数量
	public synchronized void put(int num) {
		try {
			// 如果放入数据等于cells的长度,此线程等待
			while (count == cells.length) {
				this.wait();
			}
			cells[inPos] = num;          // 向数组中放入数据
			System.out.println("在cells[" + inPos + "]中放入数据---" + cells[inPos]);
			inPos++;// 存完元素让位置加1
			if (inPos == cells.length) // 当在cells[9]放完数据后再从cells[0]开始
				inPos = 0;
			count++; // 每放一个数据count加1
			this.notify();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	public synchronized void get() {
		try {
			while (count == 0) {          // 如果 count为0,此线程等待
				this.wait();
			}
			int data = cells[outPos];    // 从数组中取出数据
			System.out.println("从cells[" + outPos + "]中取出数据" + data);
			cells[outPos] = 0;            // 取出后,当前位置的数据置0
			outPos++;                       // 取完元素让位置加1
			if (outPos == cells.length) // 当从cells[9]取完数据后再从cells[0]开始
				outPos = 0;
			count--;                        // 每取出一个元素count减1
			this.notify();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

class Input implements Runnable{		    // 输入线程类
	private Storage st ;
     private int num;                           // 定义一个变量num 
	Input(Storage st){                         // 通过构造方法接收一个Storage对象
		this.st = st;
	}
	public void run(){        
		while(true){
			if(num==10){
				break;
			}
			st.put(num++);                   // 将num存入数组,每次存入后num自增
		}
	}
}

class Output implements Runnable{	       //输出线程类
	private Storage st ;
	Output(Storage st){
		this.st = st;
	}
	public void run(){
		for(int i=0;i<10;i++){
			st.get();
		}
	}
}

public class Example2 {
	public static void main(String[] args) {
		Storage st = new Storage(); // 创建数据存储类对象
		Input input = new Input(st);	// 创建Input对象传入Storage对象
		Output output = new Output(st); 	// 创建Output对象传入Storage对象
		new Thread(input).start();		// 开启新线程
		new Thread(output).start();		// 开启新线程
	}
}
结果:

在cells[0]中放入数据---0
在cells[1]中放入数据---1
在cells[2]中放入数据---2
在cells[3]中放入数据---3
在cells[4]中放入数据---4
从cells[0]中取出数据0
从cells[1]中取出数据1
从cells[2]中取出数据2
从cells[3]中取出数据3
从cells[4]中取出数据4
在cells[0]中放入数据---5
在cells[1]中放入数据---6
在cells[2]中放入数据---7
在cells[3]中放入数据---8
在cells[4]中放入数据---9
从cells[0]中取出数据5
从cells[1]中取出数据6
从cells[2]中取出数据7
从cells[3]中取出数据8
从cells[4]中取出数据9


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值