多个线程之间也可以实现通信,原因就是多个线程共同访问同一个变量。但是这种通信机制不是 “等待/通知” ,两个线程完全是主动地读取一个共享变量。
简单的说,等待/通知机制就是一个【线程A】等待,一个【线程B】通知(线程A可以不用再等待了)。
在Java语言中,实现等待通知机制主要是用:wait()/notify()
方法实现。下面详细介绍一下这两个方法:
wait()
方法 :wait()方法是使当前执行代码的线程进行等待,wait()方法是Object类的方法,该方法用来将当前线程置入“欲执行队列”中,并且在wait()所在的代码处停止执行,直到接到通知或被中断为止。在调用wait()
方法之前,线程必须获得该对象的对象级别锁,即只能在同步方法或者同步块中调用wait()方法。在执行wait()方法后,当前线程释放锁。notify()
方法:方法notify()也要在同步方法或同步块中调用,即在调用前,线程也必须获得该对象的对象级别锁。【但是如果使用了notify(),那么执行这个notify()的代码的线程会是什么状态?】这两个方法都需要同synchronized
关键字联用。
package grammar.Thread.Chapter3;
public class TestWait {
public static void main(String[] args) {
String newString = new String("");
try {
newString.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
运行抛出如下异常:
1.java.lang.IllegalMonitorStateException
,具体的原因是:没有“对象监视器”,也就是没有同步加锁。修改如下:
public static void main(String[] args) {
String lock = new String();
System.out.println("above synchronized");
synchronized (lock) {
System.out.println("the first line");
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("after wait");
}
System.out.println("after synchronized");
}
此示例运行成功,但是会运行到lock.wait()
时卡住,因为没有notify()
唤醒它。
package InAction.ProducerAndConsumer;
import java.util.Stack;
public class Producer{
Stack<Double> stack;
//构造注入
public Producer(Stack<Double> stack ){
this.stack = stack;
}
public void produce(){
while(true) {
if (stack.size() == 0) {
synchronized (stack) {
double product = Math.random() * 10;
stack.push(product);
System.out.println("produce one product,the stack.size ="
+ stack.size());
try {
stack.wait();//阻塞
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
package InAction.ProducerAndConsumer;
import java.util.Stack;
public class Consumer{
Stack<Double> stack;
public Consumer(Stack stack){
this.stack = stack;
}
//消费消息
public void consume(){
while(true) {
synchronized (stack) {
if (stack.size() != 0) {
double temp = stack.pop();//出栈
System.out.println("consume one product" + temp
+ ",stack.size = " + stack.size());
stack.notify();//wake up producer
}
}
}
}
}
package InAction.ProducerAndConsumer;
public class ThreadOne extends Thread{
Producer producer;
//构造注入producer
public ThreadOne(Producer producer){
super();
this.producer = producer;
}
@Override
public void run() {
producer.produce();
}
}
package InAction.ProducerAndConsumer;
public class ThreadTwo extends Thread {
Consumer consumer;
//构造注入producer
public ThreadTwo(Consumer consumer){
super();
this.consumer = consumer;
}
@Override
public void run() {
consumer.consume();
}
}
package InAction.ProducerAndConsumer;
import java.util.Stack;
public class Client {
public static void main(String[] args) {
//生成或消费的记录都放在stack中
Stack<Double> stack = new Stack<Double>();
Producer producer = new Producer(stack);
Consumer consumer = new Consumer(stack);
ThreadOne threadOne = new ThreadOne(producer);
ThreadTwo threadTwo = new ThreadTwo(consumer);
threadOne.start();
threadTwo.start();
}
}
运行结果:
可以看到先生产,再消费。而且这个过程是一直持续下去的。
注:
ThreadA与TheradB类不变。
为了体现是哪个生产者在生产产品,对Producer类和Consumer类进行修改,如下:
package InAction.ProducerAndConsumer;
import java.util.Stack;
public class Producer{
Stack<Integer> stack;
//构造注入
public Producer(Stack<Integer> stack ){
this.stack = stack;
}
public void produce(){
while(true) {
if (stack.size() == 0){
synchronized (stack) {
int product = (int)(Math.random() * 10);
stack.push(product);
System.out.println(Thread.currentThread().getName()+
" produce one product "+product+
",the stack.size ="+ stack.size());
try {
stack.wait();//阻塞
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
package InAction.ProducerAndConsumer;
import java.util.Stack;
public class Consumer{
Stack<Integer> stack;
public Consumer(Stack stack){
this.stack = stack;
}
//消费消息
public void consume(){
while(true) {
synchronized (stack) {
if (stack.size() != 0) {
int temp = stack.pop();//出栈
System.out.println(Thread.currentThread().getName()+
" consume one product " + temp +
",stack.size = " + stack.size());
stack.notify();//wake up producer
}
}
}
}
}
修改Client类,使其有多个生产者生产产品:
package InAction.ProducerAndConsumer;
import java.util.Stack;
public class Client {
public static void main(String[] args) {
//生成或消费的记录都放在stack中
Stack<Integer> stack = new Stack<Integer>();
Producer producer = new Producer(stack);
Consumer consumer = new Consumer(stack);
//弄两个生产者
ThreadOne pA = new ThreadOne(producer);
ThreadOne pA1 = new ThreadOne(producer);
//仍然只有一个消费者
ThreadTwo threadTwo = new ThreadTwo(consumer);
pA.setName("pA");
pA1.setName("pB");
threadTwo.setName("cA");
pA.start();
pA1.start();
threadTwo.start();
}
}