Java多线程(5)--线程通信wait和notify

简介: Java多线程(5)--线程通信wait和notify

例题:使用两个线程打印 1-100。线程1, 线程2 交替打印。


解决:涉及wait()和notify()/notifyAll()


class Communicate implements Runnable {
    private int number = 1;
    @Override
    public void run() {
        while (true) {
            synchronized (this) {
                this.notify();
                if (number <= 100){
                    System.out.println(Thread.currentThread().getName() + "打印出" + number);
                    number++;
                    try {
                        this.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }else break;
            }
        }
    }
}
public class CommunicateTest {
    public static void main(String[] args) {
        Communicate communicate = new Communicate();
        Thread thread1 = new Thread(communicate);
        Thread thread2 = new Thread(communicate);
        thread1.setName("线程一");
        thread2.setName("线程二");
        thread1.start();
        thread2.start();
    }
}


wait():令当前线程挂起,放弃CPU、同步资源并等待,使别的线程可访问并修改共享资源,而当前线程排队等候其他线程调用notify()或notifyAll()方法唤醒,唤醒后等待重新获得对监视器的所有权后才能继续执行。


notify():唤醒正在排队等待同步资源的线程中优先级最高者结束等待。


notifyAll():唤醒正在排队等待资源的所有线程结束等待。


这三个方法只有在synchronized方法或synchronized代码块中才能使用,否则会报

java.lang.IllegalMonitorStateException异常。


这三个方法的调用者都必须是同步监视器,即如同步监视器.wait()。例如以上代码中的同步监视器是本对象this。


这三个方法是定义在Object类中的,而非Thread。


sleep() 和wait()的异同:


1.相同点:一 旦执行方法,都可以使得当前的线程进入阻塞状态。

2.不同点:①两个方法声明的位置不同: Thread类中声明sleep() ,Object类中声明wait()。②调用的要求不同: sleep() 可以在任何需要的场景下调用,wait( )必须使用在同步代码块或同步方法中。③关于是否释放同步监视器: 如果两个方法都使用在同步代码块或同步方法中,sleep()不会释放锁,wait()会释放锁。


经典例题:生产者/消费者问题


生产者(Productor)将产品交给店员(Clerk),而消费者(Customer)从店员处取走产品,店员一次只能持有固定数量的产品(比如:20),如果生产者试图生产更多的产品,店员会叫生产者停一下,如果店中有空位放产品了再通知生产者继续生产;如果店中没有产品了,店员会告诉消费者等一下,如果店中有产品了再通知消费者来取走产品。


①店员(产品):


//店员(产品)
class Clerk {
    private int productNum = 0;
    public synchronized void addProduct() {
        if (productNum < 20){
            productNum++;
            System.out.println(Thread.currentThread().getName() + ":生产的第" + productNum + "个产品");
            notifyAll();
        }else {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    public synchronized void getProduct() {
        if (productNum > 0){
            productNum--;
            System.out.println(Thread.currentThread().getName() + ":消费的第" + productNum + "个产品");
            notifyAll();
        }else {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}


②生产者:


//生产者
class Productor implements Runnable {
    private Clerk clerk;
    public Productor(Clerk clerk) {
        this.clerk = clerk;
    }
    @Override
    public void run() {
        System.out.println("生产者开始生产产品");
        while (true) {
            try {
                Thread.sleep((int) Math.random() * 1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            clerk.addProduct();
        }
    }
}


③消费者:


//消费者
class Consumer implements Runnable {
    private Clerk clerk;
    public Consumer(Clerk clerk) {
        this.clerk = clerk;
    }
    public void run() {
        System.out.println("消费者开始取走产品");
        while (true) {
            try {
                Thread.sleep((int) Math.random() * 1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            clerk.getProduct();
        }
    }
}


④主进程main


public class ProductTest {
    public static void main(String[] args) {
        Clerk clerk = new Clerk();
        Productor productor = new Productor(clerk);
        Consumer consumer = new Consumer(clerk);
        Thread thread1 = new Thread(productor);
        Thread thread2 = new Thread(consumer);
        thread1.setName("生产者");
        thread2.setName("消费者");
        thread1.start();
        thread2.start();
    }
}



相关文章
|
3天前
|
Java 机器人 程序员
Java中的线程通信:wait、notify与Condition详解
Java中的线程通信:wait、notify与Condition详解
|
3天前
|
Java
java线程之定制化通信(多轮顺序打印问题)
java线程之定制化通信(多轮顺序打印问题)
6 1
|
1天前
|
安全 Java Python
线程间通信详解
线程间通信详解
|
2天前
|
存储 监控 Java
深入探索Java BIO与NIO输入输出模型:基于文件复制和socket通信
深入探索Java BIO与NIO输入输出模型:基于文件复制和socket通信
|
1月前
|
安全 Java
深入理解Java并发编程:线程安全与性能优化
【2月更文挑战第22天】在Java并发编程中,线程安全和性能优化是两个重要的主题。本文将深入探讨这两个主题,包括线程安全的基本概念,如何实现线程安全,以及如何在保证线程安全的同时进行性能优化。
27 0
|
28天前
|
存储 安全 Java
深入理解Java并发编程:线程安全与锁机制
【5月更文挑战第31天】在Java并发编程中,线程安全和锁机制是两个核心概念。本文将深入探讨这两个概念,包括它们的定义、实现方式以及在实际开发中的应用。通过对线程安全和锁机制的深入理解,可以帮助我们更好地解决并发编程中的问题,提高程序的性能和稳定性。
|
1月前
|
安全 Java 容器
Java一分钟之-并发编程:线程安全的集合类
【5月更文挑战第19天】Java提供线程安全集合类以解决并发环境中的数据一致性问题。例如,Vector是线程安全但效率低;可以使用Collections.synchronizedXxx将ArrayList或HashMap同步;ConcurrentHashMap是高效线程安全的映射;CopyOnWriteArrayList和CopyOnWriteArraySet适合读多写少场景;LinkedBlockingQueue是生产者-消费者模型中的线程安全队列。注意,过度同步可能影响性能,应尽量减少共享状态并利用并发工具类。
34 2
|
1月前
|
安全 Java
Java中的并发编程:理解并发性与线程安全
Java作为一种广泛应用的编程语言,在并发编程方面具有显著的优势和特点。本文将探讨Java中的并发编程概念,重点关注并发性与线程安全,并提供一些实用的技巧和建议,帮助开发人员更好地理解和应用Java中的并发机制。
|
1月前
|
缓存 安全 Java
Java并发编程中的线程安全问题及解决方法
在Java编程中,线程安全是一个至关重要的问题,特别是在并发编程中。本文将探讨Java并发编程中常见的线程安全问题,包括数据竞争、死锁和内存可见性,并介绍了相应的解决方法,如使用同步锁、并发容器和原子类等技术,以确保多线程环境下程序的正确性和性能。
16 2
|
1月前
|
安全 Java 容器
Java并发编程:实现高效、线程安全的多线程应用
综上所述,Java并发编程需要注意线程安全、可见性、性能等方面的问题。合理使用线程池、同步机制、并发容器等工具,可以实现高效且线程安全的多线程应用。
25 1

热门文章

最新文章