高并发编程-线程生产者消费者的综合示例
【摘要】
文章目录
需求实现
需求
需求: 假设有10个线程,最多同时运行5个 要求: 不使用线程池,使用synchronized-wait&notifyAll机制
实现
详见...
需求
需求: 假设有10个线程,最多同时运行5个
要求: 不使用线程池,使用synchronized-wait¬ifyAll机制
实现
详见注释
package com.artisan.test;
import java.time.LocalTime;
import java.util.*;
/**
* 需求: 假设有10个线程,最多同时运行5个
* 要求: 不使用线程池,使用synchronized-wait¬ifyAll机制
*/
public class ExerciseDemo {
// 锁 Monitor
private static final LinkedList<Control> CONTROLLIST = new LinkedList();
// 同时运行的最大线程数
private static final int MAX_THREADS = 5;
/**
* 创建线程
* @param threadName 线程名称
* @return
*/
public static Thread createWorkThread(String threadName){
return new Thread(() ->{
// 加锁
synchronized (CONTROLLIST){
Optional.of(Thread.currentThread().getName() + " GOT LOCK ,BEGIN..." + LocalTime.now().withNano(0)).ifPresent(System.out::println);
// 使用while
// 当集合中运行的线程数量大于5时,wait,放弃锁,不执行
while (CONTROLLIST.size() >= MAX_THREADS){
try {
Optional.of(Thread.currentThread().getName() + " WAIT").ifPresent(System.out::println);
CONTROLLIST.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 加入到LinkedList最后
CONTROLLIST.addLast(new Control());
}
//模拟每个线程的业务,假设需要10秒才能结束
Optional.of(Thread.currentThread().getName() + " working..." + LocalTime.now().withNano(0)).ifPresent(System.out::println);
try {
Thread.sleep(10_000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 输出业务完成
Optional.of(Thread.currentThread().getName() + " END..." + LocalTime.now().withNano(0)).ifPresent(System.out::println);
// 加锁
synchronized (CONTROLLIST){
// 移除最上面的线程
CONTROLLIST.removeFirst();
// 唤醒其他所有等待的线程
CONTROLLIST.notifyAll();
}
},threadName);
}
/**
* 主流程
* @param args
*/
public static void main(String[] args) {
List<Thread> workers = new ArrayList();
Arrays.asList("T1","T2","T3","T4","T5","T6","T7","T8","T9","T10")
.stream()
.map(ExerciseDemo::createWorkThread)
.forEach(t->{
// 启动线程
t.start();
// 加入到集合列表,待后续一起join
workers.add(t);
});
// 比那里保存线程的集合,10个线程 join
workers.stream().forEach(t -> {
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
);
// 全部完成后,输出结束标识
Optional.of("DONE").ifPresent(System.out::println);
}
/**
* 没啥实质做用,仅仅是个控制标识
*/
static class Control{
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
运行日志
"E:\Program Files\Java\jdk1.8.0_161\bin\java" "-javaagent:E:\Program Files\JetBrains\IntelliJ IDEA 2017.2.4\lib\idea_rt.jar=60076:E:\Program Files\JetBrains\IntelliJ IDEA 2017.2.4\bin" -Dfile.encoding=UTF-8 -classpath "E:\Program Files\Java\jdk1.8.0_161\jre\lib\charsets.jar;E:\Program Files\Java\jdk1.8.0_161\jre\lib\deploy.jar;E:\Program Files\Java\jdk1.8.0_161\jre\lib\ext\access-bridge-64.jar;E:\Program Files\Java\jdk1.8.0_161\jre\lib\ext\cldrdata.jar;E:\Program Files\Java\jdk1.8.0_161\jre\lib\ext\dnsns.jar;E:\Program Files\Java\jdk1.8.0_161\jre\lib\ext\jaccess.jar;E:\Program Files\Java\jdk1.8.0_161\jre\lib\ext\jfxrt.jar;E:\Program Files\Java\jdk1.8.0_161\jre\lib\ext\localedata.jar;E:\Program Files\Java\jdk1.8.0_161\jre\lib\ext\nashorn.jar;E:\Program Files\Java\jdk1.8.0_161\jre\lib\ext\sunec.jar;E:\Program Files\Java\jdk1.8.0_161\jre\lib\ext\sunjce_provider.jar;E:\Program Files\Java\jdk1.8.0_161\jre\lib\ext\sunmscapi.jar;E:\Program Files\Java\jdk1.8.0_161\jre\lib\ext\sunpkcs11.jar;E:\Program Files\Java\jdk1.8.0_161\jre\lib\ext\zipfs.jar;E:\Program Files\Java\jdk1.8.0_161\jre\lib\javaws.jar;E:\Program Files\Java\jdk1.8.0_161\jre\lib\jce.jar;E:\Program Files\Java\jdk1.8.0_161\jre\lib\jfr.jar;E:\Program Files\Java\jdk1.8.0_161\jre\lib\jfxswt.jar;E:\Program Files\Java\jdk1.8.0_161\jre\lib\jsse.jar;E:\Program Files\Java\jdk1.8.0_161\jre\lib\management-agent.jar;E:\Program Files\Java\jdk1.8.0_161\jre\lib\plugin.jar;E:\Program Files\Java\jdk1.8.0_161\jre\lib\resources.jar;E:\Program Files\Java\jdk1.8.0_161\jre\lib\rt.jar;D:\IdeaProjects\mvc\target\classes" com.artisan.test.ExerciseDemo
T1 GOT LOCK ,BEGIN...00:03:41
T10 GOT LOCK ,BEGIN...00:03:41
T9 GOT LOCK ,BEGIN...00:03:41
T8 GOT LOCK ,BEGIN...00:03:41
T1 working...00:03:41
T7 GOT LOCK ,BEGIN...00:03:41
T8 working...00:03:41
T7 working...00:03:41
T10 working...00:03:41
T9 working...00:03:41
T6 GOT LOCK ,BEGIN...00:03:41
T6 WAIT
T5 GOT LOCK ,BEGIN...00:03:41
T5 WAIT
T4 GOT LOCK ,BEGIN...00:03:41
T4 WAIT
T3 GOT LOCK ,BEGIN...00:03:41
T3 WAIT
T2 GOT LOCK ,BEGIN...00:03:41
T2 WAIT
T10 END...00:03:51
T8 END...00:03:51
T2 working...00:03:51
T4 WAIT
T3 working...00:03:51
T5 WAIT
T6 WAIT
T1 END...00:03:51
T6 working...00:03:51
T5 WAIT
T4 WAIT
T9 END...00:03:51
T4 working...00:03:51
T5 WAIT
T7 END...00:03:51
T5 working...00:03:51
T2 END...00:04:01
T3 END...00:04:01
T6 END...00:04:01
T4 END...00:04:01
T5 END...00:04:01
DONE
Process finished with exit code 0
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
-
首先主线程中 初始化10个线程,分别命名为T1 … T10,先把这10个线程临时存放到集合
-
遍历集合,分别join . 不能在上一步的地方join , 这样的话就只能一个线程 一个线程的执行了(join会阻塞当前线程)
-
10个线程全部完成后,打印DONE
-
完成主要部分的编码后,就需要关注thread具体的业务逻辑了 : 定义一个锁
LinkedList<Control>
,当线程获取到锁,就将Control添加到Monitor中,如果大于规定的线程数,则wait -
业务部分并行执行,当一个线程完成后,获取锁,从Monitor中移除一个Control, 然后notifyAll所有正在等待的线程
符合需求 ,OK
文章来源: artisan.blog.csdn.net,作者:小小工匠,版权归原作者所有,如需转载,请联系作者。
原文链接:artisan.blog.csdn.net/article/details/102512490
【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)