涉及到的方法:
1、wait():一旦执行次方法,当前线程就会处于阻塞状态,并自动释放同步监视器;
2、notify():唤醒执行了wait()的线程,如果有多个线程执行了wait()方法,则优先唤醒优先级高的线程,如果优先级相同,则随即唤醒一个;
3、notifyAll():唤醒所有执行了wait()的线程。
说明:
1、wait()、notify()、notifyAll()三个方法必须使用在同步代码块或同步方法中;
2、wait()、notify()、notifyAll()三个方法的调用者必须是同步监视器;
3、 wait()、notify()、notifyAll()三个方法是定义在java.lang.Object类中的,因为同步监视器可以是任意类对象。
sleep()和wait()有何区别?
1、sleep()方法声明在Thread类中,wait()声明在Object类中;
2、sleep()方法可以用在任意需要的位置,wait()只能用在同步代码块或同步方法中;
3、sleep()方法不会释放同步监视器,wait()方法会释放同步监视器。
线程通信之生产者与消费者问题:
1.需求:
生产者(Productor)将产品交给店员(Clerk),而消费者(Customer)从店员处 取走产品,店员一次只能持有固定数量的产品(比如:20),如果生产者试图 生产更多的产品,店员会叫生产者停一下,如果店中有空位放产品了再通 知生产者继续生产;如果店中没有产品了,店员会告诉消费者等一下,如 果店中有产品了再通知消费者来取走产品。
2.分析:
- 线程:生产者线程、消费者线程
- 共享数据:店员/产品数量
- 线程创建方式:继承Thread(随意)
- 解决线程安全问题:同步方法(随意)
3.代码:
package cn.jingpengchong.test;
class Clerk{
//共享数据店员实际上是共同操作产品数量
private int productNum = 0;
//控制产品的生产
public synchronized void product(){
if (productNum < 20){
notify();
productNum ++;
System.out.println(Thread.currentThread().getName()+":生产产品,编号-->"+productNum);
}else{
//等待
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//控制产品的消费
public synchronized void consum(){
if (productNum > 0){
notify();
System.out.println(Thread.currentThread().getName()+":消费产品,编号-->"+productNum);
productNum --;
}else{
//等待
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Productor extends Thread{
private Clerk clerk = null;
public Productor(Clerk clerk){
this.clerk = clerk;
}
@Override
public void run() {
while(true) {
clerk.product();
//使得线程不要执行得太快,便于观察
try {
sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Customer extends Thread{
private Clerk clerk = null;
public Customer(Clerk clerk){
this.clerk = clerk;
}
@Override
public void run() {
while(true) {
clerk.consum();
//使得线程不要执行得太快,便于观察
try {
sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class PAndCModel {
public static void main(String[] args) {
Clerk clerk = new Clerk();
Productor p = new Productor(clerk);
Customer c = new Customer(clerk);
p.setName("生产者");
c.setName("消费者");
p.start();
c.start();
}
}