在上一篇博客 Java多线程之线程安全与线程同步(锁) 介绍一下线程安全与线程同步相关概念,在本篇博客将使用输入、输出Demo模拟线程通信。
线程通讯
1、何为线程通信
所谓线程通信
,通俗的来说,就是多个线程之间需要进行信息交换,达到改变线程执行顺序、状态的目的。
2、线程通信Demo
Input进程
负责往cache中写入信息,Output进程
负责读出cache中的信息。
那么这就有几个逻辑问题了,只有Input进程
往cache中写入了内容,Output进程
才能进行读取信息,同样只有Output进程
读出了信息,Input进程
才能继续写入信息到cache。
代码初步实现:
package cn.hestyle.demo;
class MyCache{
public String key;
public String value;
/**标记cache是否为空*/
public boolean isEmpty = true;
@Override
public String toString() {
return "MyCache{" +
"key='" + key + '\'' +
", value='" + value + '\'' +
", isEmpty=" + isEmpty +
'}';
}
}
/**
* 写入进程
*/
class InputThread extends Thread{
private int count = 0;
private MyCache myCache;
public InputThread(MyCache myCache) {
this.myCache = myCache;
}
@Override
public void run() {
//往myCache写入内容
while (true) {
if (myCache.isEmpty) {
if (count == 0) {
myCache.key = "username";
myCache.value = "hestyle";
} else {
myCache.key = "password";
myCache.value = "123456";
}
count = (count + 1) % 2;
//写入了内容,标记cache不为空
myCache.isEmpty = false;
}
}
}
}
/**
* 读出进程
*/
class OutputThread extends Thread{
private MyCache myCache;
public OutputThread(MyCache myCache) {
this.myCache = myCache;
}
@Override
public void run() {
//往myCache读出内容
while (true) {
if (!myCache.isEmpty) {
System.out.println(myCache);
//读出了内容,标记cache为空
myCache.isEmpty = true;
}
}
}
}
/**
* description: demo_01
*
* @author hestyle
* @version 1.0
* @className multi_thread_project_01->MultiThreadDemo01
* @date 2020-02-09 15:35
**/
public class MultiThreadDemo01 {
public static void main(String[] args) {
//创建一个公共cache
MyCache myCache = new MyCache();
//创建input、output进程
InputThread inputThread = new InputThread(myCache);
OutputThread outputThread = new OutputThread(myCache);
//启动两个线程
inputThread.start();
outputThread.start();
}
}
控制台输出:
这里的MyCache.isEmpty
确实起到了Input进程
、Output进程
交换信息的作用,实现了先写入再读取,读取后再写入的逻辑。
但是这个实现存在一个问题,就是非常耗CPU资源,Input进程
不间断的去查询MyCache.isEmpty
,判断是否可以写入信息,Output进程
不间断的去查询MyCache.isEmpty
,判断是否可以读取信息。
下面我们进一步完善逻辑,当Input进程
写入后,通知Output进程
读取,Output进程
读取完后,接着就通知Input进程
继续写入。
首先是引入锁的机制,对于MyCache的读、写只能有一个进程在进行。
关于锁、线程同步,可以参考上一篇博客 Java多线程之线程安全与线程同步(锁)
package cn.hestyle.demo;
class MyCache{
public String key;
public String value;
/**标记cache是否为空*/
public boolean isEmpty = true;
@Override
public String toString() {
return "MyCache{" +
"key='" + key + '\'' +
", value='" + value + '\'' +
", isEmpty=" + isEmpty +
'}';
}
}
/**
* 写入进程
*/
class InputThread extends Thread{
private int count = 0;
private MyCache myCache;
public InputThread(MyCache myCache) {
this.myCache = myCache;
}
@Override
public void run() {
//往myCache写入内容
while (true) {
//同步代码块,使用myCache作为锁
synchronized (myCache) {
if (!myCache.isEmpty) {
//如果myCache不为空,则input进程计入睡眠状态
try {
myCache.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (count == 0) {
myCache.key = "username";
myCache.value = "hestyle";
} else {
myCache.key = "password";
myCache.value = "123456";
}
count = (count + 1) % 2;
//写入了内容,标记cache不为空
myCache.isEmpty = false;
//写入完毕后,接着去通知正在等待读取的线程
myCache.notifyAll();
}
}
}
}
/**
* 读出进程
*/
class OutputThread extends Thread{
private MyCache myCache;
public OutputThread(MyCache myCache) {
this.myCache = myCache;
}
@Override
public void run() {
//往myCache读出内容
while (true) {
//同步代码块,使用myCache作为锁
synchronized (myCache) {
if (myCache.isEmpty) {
//如果cache为空,则input进程进入等待状态
try {
myCache.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(myCache);
//读出了内容,标记cache为空
myCache.isEmpty = true;
//input进程读取完毕后,接着去通知正在等待写入的进程
myCache.notifyAll();
}
}
}
}
/**
* description: demo_01
*
* @author hestyle
* @version 1.0
* @className multi_thread_project_01->MultiThreadDemo01
* @date 2020-02-09 15:35
**/
public class MultiThreadDemo01 {
public static void main(String[] args) {
//创建一个公共cache
MyCache myCache = new MyCache();
//创建input、output进程
InputThread inputThread = new InputThread(myCache);
OutputThread outputThread = new OutputThread(myCache);
//启动两个线程
inputThread.start();
outputThread.start();
}
}
3、wait()、notify()、notifyAll()方法
wait()
、notify()
、notifyAll()
是三个定义在Object
类里的方法,可以用来控制线程的状态。这三个方法最终调用的都是jvm级的native方法。
wait()方法: 使持有该对象的线程把该对象的控制权交出去,然后处于等待状态。
notify()方法: 通知某个正在等待这个对象的控制权的线程可以继续运行。
notifyAll()方法: 通知所有等待这个对象控制权的线程继续运行。
1、对于sleep()方法,属于Thread类,而wait()方法,属于Object类中
2、sleep()方法不会释放锁,wait()方法会释放锁。
sleep()方法导致了程序暂停执行指定的时间,让出cpu该其他线程,
但是他的监控状态依然保持者,当指定的时间到了又会自动恢复运行状态。
在调用sleep()方法的过程中,线程不会释放对象锁。
而当调用wait()方法的时候,线程会放弃对象锁,进入等待此对象的等待锁定池,
只有针对此对象调用notify()方法后本线程才进入对象锁定池准备获取对象锁进入运行状态。
以上就是Java多线程之线程通信(Demo演示),主要是需要理解锁机制、线程五个状态相关内容。