Java线程间通信

简介: 前一例只是简单地为特定对象或方法加锁,但有时情况会更加复杂,如果两个线程之间有依赖关系,线程之间必须进行通信,互相协调才能完成工作。

前一例只是简单地为特定对象或方法加锁,但有时情况会更加复杂,如果两个线程之间有依

赖关系,线程之间必须进行通信,互相协调才能完成工作。


例如有一个经典的堆栈问题,一个线程生成了一些数据,将数据压栈;另一个线程消费了这些数据, 将数据出栈。这两个线程互相依赖,当堆栈为空时,消费线程无法取出数据时,应该通知生成线程添 加数据;当堆栈已满时,生产线程无法添加数据时,应该通知消费线程取出数据。


为了实现线程间通信,需要使用Object类中声明的5个方法:


void wait():使当前线程释放对象锁,然后当前线程处于对象等待队列中阻塞状态。

void wait(long timeout):同wait()方法,等待timeout毫秒时间。

void wait(long timeout, int nanos):同wait()方法,等待timeout毫秒加nanos纳秒时间。

void notify():当前线程唤醒此对象等待队列中的一个线程。

void notifyAll():当前线程唤醒此对象等待队列中的所有线程。

如图所示:

5.png

线程有多种方式进入阻塞状态,除了通过wait()外还 有,加锁的方式和其他方式

下面看看消费和生产示例中堆栈类代码:

//堆栈类
public class Stack {
//    堆栈指针初始值为0
    private int pointer = 0;
//    堆栈有五个字符的空间
    private char[] data = new char[5];
//    压栈方法,加上互斥锁
    public synchronized void push(char c){
//        堆栈已满,不能压栈
        while (pointer == data.length){
            try{
//                等待,直到所有数据出栈
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
//        通知其他线程把数据出栈
        this.notify();
//        数据压栈
        data[pointer] = c;
//        指针向上移动
        pointer++;
    }
//    出栈方法
    public synchronized char pop(){
//        堆栈无数据,不能出栈
        while (pointer == 0){
            try {
//                等待其他线程把数据压出栈
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //        通知其他线程把数据出栈
        this.notify();
        //        指针向下移动
        pointer--;
        return data[pointer];
    }
}

上述代码实现了同步堆栈类,该堆栈有最多5个元素的空间,代码声明了压栈方法push(),该方 法是一个同步方法,在该方法中首先判断是否堆栈已满,如果已满不能压栈,调用this.wait()让当前线 程进入对象等待状态中。如果堆栈未满,程序会往下运行调用this.notify()唤醒对象等待队列中的一个线程。


调用代码:

public class HelloWorld {
    public static void main(String[] args) {
        Stack stack = new Stack();
//        下面的消费者和生产者所操作的是同一个堆栈对象stack
//        生产者线程
        Thread producer = new Thread(() ->{
            char c ;
            for (int i = 0;i<10;i++){
//                随机产生10个字符
                c = (char)(Math.random()*26 + 'a');
//               把字符压栈
                stack.push(c);
//                打印字符
                System.out.println("生产:"+c);
                try {
//                    每生产一个字符就线程休眠
                    Thread.sleep((int)(Math.random()*1000));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
//        消费者线程
        Thread consumer =  new Thread(() ->{
            char c;
            for (int i = 0;i<10;i++){
//                从堆栈中读取字符
                c = stack.pop();
//               打印字符
                System.out.println("消费:"+c);
                try {
//                    每读取一个字符就线程休眠
                    Thread.sleep((int)(Math.random()*1000));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
//        启动生产者线程
        producer.start();
//        启动消费者线程
        consumer.start();
    }
}

运行结果:

生产:x
消费:x
生产:s
消费:s
生产:d
消费:d
生产:p
消费:p
生产:v
消费:v
生产:r
消费:r
生产:p
消费:p
生产:j
消费:j
生产:j
消费:j
生产:d
消费:d
相关文章
|
12天前
|
安全 Java 调度
Java编程时多线程操作单核服务器可以不加锁吗?
Java编程时多线程操作单核服务器可以不加锁吗?
32 2
|
1天前
|
Java 关系型数据库 MySQL
如何用java的虚拟线程连接数据库
本文介绍了如何使用Java虚拟线程连接数据库,包括设置JDK版本、创建虚拟线程的方法和使用虚拟线程连接MySQL数据库的示例代码。
14 6
如何用java的虚拟线程连接数据库
|
4天前
|
Java 数据库 UED
Java的多线程有什么用
Java的多线程技术广泛应用于提升程序性能和用户体验,具体包括:提高性能,通过并行执行充分利用多核CPU;保持响应性,使用户界面在执行耗时操作时仍流畅交互;资源共享,多个线程共享同一内存空间以协同工作;并发处理,高效管理多个客户端请求;定时任务,利用`ScheduledExecutorService`实现周期性操作;任务分解,将大任务拆分以加速计算。多线程尤其适用于高并发和并行处理场景。
|
16天前
|
存储 缓存 Java
java线程内存模型底层实现原理
java线程内存模型底层实现原理
java线程内存模型底层实现原理
|
19小时前
|
Java 调度
Java一个线程的生命周期详解
Java中,一个线程的生命周期分为五个阶段:NEW(新建),RUNNABLE(可运行),BLOCKED(阻塞),WAITING(等待),TERMINATED(终止)。线程创建后处于新建状态,调用start方法进入可运行状态,执行中可能因等待资源进入阻塞或等待状态,正常完成或异常终止后进入终止状态。各状态间可相互转换,构成线程的生命周期。
|
1天前
|
Java 开发者
农行1面:Java如何保证线程T1,T2,T3 顺序执行?
本文探讨了如何保证线程T1、T2、T3的顺序执行,这是农行面试中的一道题目,旨在考察候选人对多线程基础、同步机制、线程间通信及Java并发包的掌握情况。文章详细介绍了六种方法:`join()`、`CountDownLatch`、`Semaphore`、单线程池、`synchronized` 和 `CompletableFuture`,并通过示例代码展示了每种方法的具体实现。这些方法不仅适用于面试备考,还能帮助开发者更好地理解和掌握线程同步技术。
20 2
|
19小时前
|
Java API 调度
Java 多线程编程详解
《Java多线程编程详解》深入浅出地讲解了Java平台下的多线程核心概念、API使用及最佳实践。从基础理论到实战案例,本书帮助读者掌握并发编程技巧,提升软件开发中的效率与性能,是Java开发者不可或缺的参考指南。
|
1天前
|
Java
用java实现Client和Server之间的互相通信
本文介绍了如何使用Java实现客户端和服务器之间的通信,包括服务器端创建ServerSocket、接受客户端连接、读取和发送消息,以及客户端创建Socket连接、发送和接收消息的完整过程。
6 0
用java实现Client和Server之间的互相通信
|
21天前
|
缓存 Java 应用服务中间件
Java虚拟线程探究与性能解析
本文主要介绍了阿里云在Java-虚拟-线程任务中的新进展和技术细节。
|
18天前
|
Java 开发者
Java中的多线程基础与应用
【9月更文挑战第22天】在Java的世界中,多线程是一块基石,它支撑着现代并发编程的大厦。本文将深入浅出地介绍Java中多线程的基本概念、创建方法以及常见的应用场景,帮助读者理解并掌握这一核心技术。