java 编写线程公共类_Java实现线程间通信方式

线程间通信的模型:

共享内存

消息传递

我们来做道题理解一下

题目: 有两个线程A、B,A线程向一个集合里面依次添加元素"abc"字符串,一共添加十次,当添加到第五次的时候,希望B线程能够收到A线程的通知,然后B线程执行相关的业务操作。

方法1: 使用volatile关键字

使用共享内存的思想,大致意思就是多个线程同时监听一个变量,当这个变量发生变化的时候 ,线程能够感知并执行相应的业务。

是最简单的一种实现方式。

package com.ronnie.leetcode.tel;

import java.util.ArrayList;

import java.util.List;

public class TestSync01 {

// 定义一个共享变量来实现通信,它需要是volatile修饰,否则线程不能及时感知

static volatile boolean notice = false;

public static void main(String[] args) {

List list = new ArrayList<>();

// 实现线程A

Thread threadA = new Thread(() ->{

for (int i = 1; i <= 10; i++){

list.add("nga");

System.out.println("线程A向列表中添加一个元素, 此时list中元素个数为: " + list.size());

try {

Thread.sleep(500);

} catch (InterruptedException e){

e.printStackTrace();

}

if (list.size() == 5)

notice = true;

}

});

// 实现线程B

Thread threadB = new Thread(() -> {

while (true){

if (notice){

System.out.println("线程N收到通知, 开始执行自己的业务: ");

break;

}

}

});

// 需要先启动线程B

threadB.start();

try {

Thread.sleep(1000);

} catch (InterruptedException e) {

e.printStackTrace();

}

// 再启动线程A

threadA.start();

}

}

实际运行结果与我们想的有些出入

线程A向列表中添加一个元素, 此时list中元素个数为: 1

线程A向列表中添加一个元素, 此时list中元素个数为: 2

线程A向列表中添加一个元素, 此时list中元素个数为: 3

线程A向列表中添加一个元素, 此时list中元素个数为: 4

线程A向列表中添加一个元素, 此时list中元素个数为: 5

线程A向列表中添加一个元素, 此时list中元素个数为: 6

线程N收到通知, 开始执行自己的业务:

线程A向列表中添加一个元素, 此时list中元素个数为: 7

线程A向列表中添加一个元素, 此时list中元素个数为: 8

线程A向列表中添加一个元素, 此时list中元素个数为: 9

线程A向列表中添加一个元素, 此时list中元素个数为: 10

将try catch放到if判断之后则能达到预期的输出

线程A向list中添加一个元素,此时list中的元素个数为:1

线程A向list中添加一个元素,此时list中的元素个数为:2

线程A向list中添加一个元素,此时list中的元素个数为:3

线程A向list中添加一个元素,此时list中的元素个数为:4

线程A向list中添加一个元素,此时list中的元素个数为:5

线程B收到通知,开始执行自己的业务...

线程A向list中添加一个元素,此时list中的元素个数为:6

线程A向list中添加一个元素,此时list中的元素个数为:7

线程A向list中添加一个元素,此时list中的元素个数为:8

线程A向list中添加一个元素,此时list中的元素个数为:9

线程A向list中添加一个元素,此时list中的元素个数为:10

原因是:

在第5次的时候线程B从阻塞状态过渡了可以竞争锁的状态,但是它并不一定就能立刻获取CPU的执行权

方法2: 使用Object类的wait()和notify() 方法

实现方式: 消息传递

需要注意的是:

wait和 notify必须配合synchronized使用,wait方法释放锁,notify方法不释放锁

package com.ronnie.leetcode.tel;

import java.util.ArrayList;

public class TestSync02 {

public static void main(String[] args) {

// 定义一个锁对象

Object lock = new Object();

ArrayList list = new ArrayList<>();

// 实现线程A

Thread threadA = new Thread(() -> {

synchronized (lock){

for (int i = 1; i <= 10; i++){

list.add("nga");

System.out.println("线程A向list中添加一个元素,此时list中的元素个数为:" + list.size());

try {

Thread.sleep(500);

} catch (InterruptedException e) {

e.printStackTrace();

}

if (list.size() == 5)

// 唤醒 B线程

lock.notify();

}

}

});

// 实现线程B

Thread threadB = new Thread(() -> {

while (true){

synchronized (lock){

if(list.size() != 5){

try {

lock.wait();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

System.out.println("线程B收到通知,开始执行自己的业务...");

}

}

});

// 需要先启动线程B

threadB.start();

try {

Thread.sleep(1000);

} catch (InterruptedException e) {

e.printStackTrace();

}

// 再启动线程A

threadA.start();

}

}

执行结果

线程A向list中添加一个元素,此时list中的元素个数为:1

线程A向list中添加一个元素,此时list中的元素个数为:2

线程A向list中添加一个元素,此时list中的元素个数为:3

线程A向list中添加一个元素,此时list中的元素个数为:4

线程A向list中添加一个元素,此时list中的元素个数为:5

线程A向list中添加一个元素,此时list中的元素个数为:6

线程A向list中添加一个元素,此时list中的元素个数为:7

线程A向list中添加一个元素,此时list中的元素个数为:8

线程A向list中添加一个元素,此时list中的元素个数为:9

线程A向list中添加一个元素,此时list中的元素个数为:10

线程B收到通知,开始执行自己的业务...

线程A发出notify()唤醒通知之后,依然是走完了自己线程的业务之后,线程B才开始执行,这也正好说明了,notify()方法不释放锁,而wait()方法释放锁。

方法3: 使用JUC工具类 CountDownLatch()

package com.ronnie.leetcode.tel;

import java.util.ArrayList;

import java.util.concurrent.CountDownLatch;

public class TestSync03 {

public static void main(String[] args) {

CountDownLatch countDownLatch = new CountDownLatch(1);

ArrayList list = new ArrayList<>();

// 实现线程A

Thread threadA = new Thread(() -> {

for (int i = 0; i <= 10; i++){

list.add("pcr");

System.out.println("线程A向list中添加一个元素,此时list中的元素个数为:" + list.size());

if (list.size() == 5)

countDownLatch.countDown();

try {

Thread.sleep(500);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

});

// 实现线程B

Thread threadB = new Thread(() -> {

while (true){

if (list.size() != 5){

try {

countDownLatch.await();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

System.out.println("线程B收到通知,开始执行自己的业务...");

break;

}

});

// 先启动线程B

threadB.start();

try {

Thread.sleep(1000);

} catch (InterruptedException e) {

e.printStackTrace();

}

// 在启动线程A

threadA.start();

}

}

执行结果

线程A向list中添加一个元素,此时list中的元素个数为:1

线程A向list中添加一个元素,此时list中的元素个数为:2

线程A向list中添加一个元素,此时list中的元素个数为:3

线程A向list中添加一个元素,此时list中的元素个数为:4

线程A向list中添加一个元素,此时list中的元素个数为:5

线程B收到通知,开始执行自己的业务...

线程A向list中添加一个元素,此时list中的元素个数为:6

线程A向list中添加一个元素,此时list中的元素个数为:7

线程A向list中添加一个元素,此时list中的元素个数为:8

线程A向list中添加一个元素,此时list中的元素个数为:9

线程A向list中添加一个元素,此时list中的元素个数为:10

线程A向list中添加一个元素,此时list中的元素个数为:11

方法4: 使用ReentrantLock结合Condition

package com.ronnie.leetcode.tel;

import java.util.ArrayList;

import java.util.concurrent.locks.Condition;

import java.util.concurrent.locks.ReentrantLock;

public class TestSync04 {

public static void main(String[] args) {

ReentrantLock lock = new ReentrantLock();

Condition condition = lock.newCondition();

ArrayList list = new ArrayList<>();

// 实现线程A

Thread threadA = new Thread(() -> {

lock.lock();

for (int i = 0; i <= 10; i++){

list.add("pcr");

System.out.println("线程A向list中添加一个元素,此时list中的元素个数为:" + list.size());

try {

Thread.sleep(500);

} catch (InterruptedException e) {

e.printStackTrace();

}

if (list.size() == 5)

condition.signal();

}

});

// 实现线程B

Thread threadB = new Thread(() -> {

lock.lock();

if (list.size() != 5){

try {

condition.await();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

System.out.println("线程B收到通知,开始执行自己的业务...");

lock.unlock();

});

// 先启动线程B

threadB.start();

try {

Thread.sleep(1000);

} catch (InterruptedException e) {

e.printStackTrace();

}

// 在启动线程A

threadA.start();

}

}

执行结果

线程A向list中添加一个元素,此时list中的元素个数为:1

线程A向list中添加一个元素,此时list中的元素个数为:2

线程A向list中添加一个元素,此时list中的元素个数为:3

线程A向list中添加一个元素,此时list中的元素个数为:4

线程A向list中添加一个元素,此时list中的元素个数为:5

线程A向list中添加一个元素,此时list中的元素个数为:6

线程A向list中添加一个元素,此时list中的元素个数为:7

线程A向list中添加一个元素,此时list中的元素个数为:8

线程A向list中添加一个元素,此时list中的元素个数为:9

线程A向list中添加一个元素,此时list中的元素个数为:10

线程A向list中添加一个元素,此时list中的元素个数为:11

可以看到线程B在被A唤醒之后由于没有获取锁还是不能立即执行,也就是说,A在唤醒操作之后,并不释放锁。

与Object类的wait()和notify()一样。

方法5: 基本LockSupport实现线程间的阻塞和唤醒(推荐)

优点:

灵活

不需要关注是等待线程先进行还是唤醒线程先运行

需要知道线程的名字

package com.ronnie.leetcode.tel;

import java.util.ArrayList;

import java.util.concurrent.locks.LockSupport;

public class TestSync05 {

public static void main(String[] args) {

ArrayList list = new ArrayList<>();

// 实现线程B

final Thread threadB = new Thread(() -> {

if (list.size() != 5) {

LockSupport.park();

}

System.out.println("线程B收到通知,开始执行自己的业务...");

});

// 实现线程A

Thread threadA = new Thread(() -> {

for (int i = 1; i <= 10; i++){

list.add("pcr");

System.out.println("线程A向list中添加一个元素,此时list中的元素个数为:" + list.size());

if (list.size() == 5)

LockSupport.unpark(threadB);

try {

Thread.sleep(500);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

});

threadA.start();

threadB.start();

}

}

执行结果

线程A向list中添加一个元素,此时list中的元素个数为:1

线程A向list中添加一个元素,此时list中的元素个数为:2

线程A向list中添加一个元素,此时list中的元素个数为:3

线程A向list中添加一个元素,此时list中的元素个数为:4

线程A向list中添加一个元素,此时list中的元素个数为:5

线程B收到通知,开始执行自己的业务...

线程A向list中添加一个元素,此时list中的元素个数为:6

线程A向list中添加一个元素,此时list中的元素个数为:7

线程A向list中添加一个元素,此时list中的元素个数为:8

线程A向list中添加一个元素,此时list中的元素个数为:9

线程A向list中添加一个元素,此时list中的元素个数为:10

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值