线程通信
线程通讯指的是多个线程通过消息传递实现相互牵制,相互调度,即线程间的相互作用。
涉及三个方法:
.wait一旦执行此方法,当前线程就进入阻塞状态,并释放同步监视器。
.notify一旦执行此方法,就会唤醒被wait的一个线程。如果有多个线程被wait,就唤醒优先级高的那个。
.notifyAll一旦执行此方法,就会唤醒所有被wait的线程。
说明:
.wait(),notify(),notifyAll()三个方法必须使用在同步代码块或同步方法中。
.wait(),notify(),notifyAll()三个方法是定义在java.lang.Object类中
创建两个线程,分别命名为线程一、线程二,使之交替打印1-100的数。
public class Wait_Thread extends Thread{
static int num = 1;
static Object obj=new Object();
@Override
public void run() {
while (true){
synchronized (obj){
obj.notify();
if(num<=100) {
System.out.println(Thread.currentThread().getName() +num++);
}else {
break;
}
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
public class Wait_Test {
public static void main(String[] args) {
Wait_Thread wt1 = new Wait_Thread();
wt1.setName("线程1:");
Wait_Thread wt2 = new Wait_Thread();
wt2.setName("线程2:");
wt1.start();
wt2.start();
}
}
经典例题:生产者/消费者问题
生产者(Productor)将产品放在柜台(Counter),而消费者(Customer)从柜台处取走产品,生产者一次只能生产固定数量的产品(比如:1), 这时柜台中不能再放产品,此时生产者应停止生产等待消费者拿走产品,此时生产者唤醒消费者来取走产品,消费者拿走产品后,唤醒生产者,消费者开始等待.
import java.util.Random;
public class Counter_Thread extends Thread{
static int counter = 5;
static Object obj = new Object();
Random random = new Random();
@Override
public void run() {
while (true){
synchronized (obj){
if(counter>0){
obj.notify();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
int a = random.nextInt(2);
if(counter<a+1){
System.out.println("消费者需要"+(a+1)+"件产品,柜台产品量为"+counter+"件,最终消费者拿走了所以的产品,目前还剩0件产品!");
counter-=counter;
}else {
counter-=(a+1);
System.out.println(Thread.currentThread().getName()+"拿了"+(a+1)+"件产品,目前还剩"+counter+"件产品!");}
if(counter==0){
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}else {
obj.notify();
int s = random.nextInt(5);
counter+=(s+5);
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"往柜台放"+(s+5)+"了件产品,目前还剩"+counter+"件产品");
if(counter>0){
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
}
public class Counter_Test {
public static void main(String[] args) {
Counter_Thread counter_thread1 = new Counter_Thread();
counter_thread1.setName("消费者");
counter_thread1.start();
Counter_Thread counter_thread2 = new Counter_Thread();
counter_thread2.setName("生产者");
counter_thread2.start();
}
}
在实现柜台摆放时,个人认为重点并不是加锁的位置,而是释放锁的位置,当柜台的产品量为0时,则此时处于缺货状态,这时就应该让消费者线程等待,让出CPU使用权,并释放锁,让生产者线程获取CPU使用权,并拿到锁并执行放置产品行为,当产品在柜台的数量大于0时,此时让生产者线程等待,并且释放等待区的消费者线程,当消费者把柜台产品数量拿为零时,继续时消费者线程等待,并释放等待区的生成者,以此循环下去。