线程通信(生产者消费者问题)
**线程通讯指的是:**多个线程通过消息传递实现相互牵制,相互调度,即线程间的相互作用。
涉及三个方法:
.wait一旦执行此方法,当前线程就进入阻塞状态,并释放同步监视器(锁)。
.notify一旦执行此方法,**就会唤醒被wait的一个线程。**如果有多个线程被wait,就唤醒优先级高的那个。
.notifyAll一旦执行此方法,就会唤醒所有被wait的线程。
说明:
.wait(),notify(),notifyAll()三个方法必须使用在同步代码块或同步方法中。
.wait(),notify(),notifyAll()三个方法是定义在java.lang.Object类中(注意调用它的类)
1.实现线程交替执行
1.用Lock锁实现
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
//用Lock锁实现线程交替输出
public class ThreadDemo extends Thread {
static int num = 0;
static Lock lock = new ReentrantLock();
static Condition con = lock.newCondition();
//当使用lock锁实现线程同步时,要实现Condition类(static Condition con = lock.newCondition();)
@Override
public void run() {
while (true) {
lock.lock();
con.signal();//线程唤醒
if (num < 100) {
num++;
System.out.println(Thread.currentThread().getName() + ":" + num);
}
try {
con.await();//线程阻塞
lock.unlock();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
如果在lock锁中执行con.signal();//线程唤醒与con.await();//线程阻塞的方法,
需要实现Condition类(Condition con = lock.newCondition();)否则会出现异常
2.经典例题:生产者/消费者问题
生产者(Productor)将产品放在柜台(Counter),而消费者(Customer)从柜台处取走产品,生产者一次只能生产固定数量的产品(比如:1), 这时柜台中不能再放产品,此时生产者应停止生产等待消费者拿走产品,此时生产者唤醒消费者来取走产品,消费者拿走产品后,唤醒生产者,消费者开始等待
解题思路:①先定义一个柜台类,在柜台类中确定商品的变量,写入生产者生产商品的方法add(),在写入消费者消费商品的方法sub()
public class Counter {
static int num=0;//柜台商品数
static Lock lock=new ReentrantLock();
static Condition con=lock.newCondition();
//生产者生产
public void add(){
lock.lock();
con.signal();
if (num==0){
num++;
System.out.println("生产者生产");
}else{
try {
con.await();
lock.unlock();
} catch (InterruptedException e) {
lock.unlock();
}
}
}
//消费者消费
public void sub(){
lock.lock();
con.signal();
if (num==1){
num--;
System.out.println("消费者消费");
}else{
try {
con.await();
lock.unlock();
} catch (InterruptedException e) {
lock.unlock();
}
}
}
}
②生产者类继承Thread类,重写run方法,调用add方法,创建含参的构造方法(确保两个线程用的是一个柜台)
public class Productor extends Thread{
Counter c;
public Productor(Counter c) {
this.c = c;
}
@Override
public void run() {
while (true){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
c.add();
}
}
}
③消费者同理
public class Customer extends Thread {
Counter c;
public Customer(Counter c) {
this.c = c;
}
@Override
public void run() {
while (true){
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
c.sub();
}
}
}
④测试类
public class Test {
public static void main(String[] args) {
Counter c=new Counter();
Customer customer=new Customer(c);
Productor productor=new Productor(c);
customer.start();
productor.start();
}
}