- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章Java多线程之Worker Thread模式由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
Worker的意思是工作的人,在Worker Thread模式中,工人线程Worker thread会逐个取回工作并进行处理,当所有工作全部完成后,工人线程会等待新的工作到来.
Worker Thread模式也被成为Background Thread(背景线程)模式,另外,如果从保存多个工人线程的场所这一点看,我们也可以称这种模式为Thread Pool模式.
创建表示工作请求的Request并将其传递给Channel。在示例程序中,ClientThread相当于该角色.
Channel角色接受来自于Client的Request,并将其传递给Worker。在示例程序中,Channel相当于该角色.
Worker角色从Channel中获取Request,并进行工作,当一项工作完成后,它会继续去获取另外的Request,在示例程序中,WorkerThread相当于该角色.
Request角色是表示工作的角色,Request角色中保存了进行工作所必须的信息,在示例程序中,Request相当于该角色.
想象一个场景,一个工厂在生产玩具,在一个车间里,有几个工人,每次生产部件准备好车间外的人就将部件放到车间的一个桌子上,工人每次做完一个玩具就从桌子上取部件。在这里,注意到,部件并不是直接交给工人的,另外一点,工人并不是做完一个部件就回家换个新人,后者在现实有点滑稽,但是在程序中却对应一个典型的线程使用方法:线程池.
所谓线程池,就是对线程的复用,当线程执行完任务之后就继续取其他任务执行,而不是销毁启动新线程执行其他任务。因为线程的启动对于系统性能开销比较大,所以这样对于系统性能的提高很有好处.
首先是请求,即玩具的部件 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
public
class
Request {
private
final
String name;
private
final
int
number;
public
Request(String name,
int
number) {
this
.name = name;
this
.number = number;
}
public
void
execute(){
System.out.println(Thread.currentThread().getName()+
" executed "
+
this
);
}
@Override
public
String toString() {
return
"Request=> "
+
"No."
+ number +
" Name."
+ name;
}
}
|
也就是拥有name和number并且execute的时候打印出字段的一个简单类.
ClientThread,负责将请求放入RequestQueue中,即将部件放到桌子上.
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
|
public
class
ClientThread
extends
Thread {
private
static
final
Random random =
new
Random(System.currentTimeMillis());
private
final
Channel channel;
public
ClientThread(String name, Channel channel) {
super
(name);
this
.channel = channel;
}
@Override
public
void
run() {
try
{
for
(
int
i =
0
;
true
; i++) {
Request request =
new
Request(getName(),i);
this
.channel.put(request);
Thread.sleep(random.nextInt(1_000));
}
}
catch
(Exception e) {
}
}
}
|
Channel类,可以当做车间 。
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
|
public
class
Channel {
private
final
static
int
MAX_REQUEST =
100
;
private
final
Request[] requestQueue;
private
final
WorkerThread[] workerPool;
private
int
head;
private
int
tail;
private
int
count;
public
Channel(
int
workers) {
this
.requestQueue =
new
Request[MAX_REQUEST];
this
.head =
0
;
this
.tail =
0
;
this
.count =
0
;
this
.workerPool =
new
WorkerThread[workers];
this
.init();
}
private
void
init() {
for
(
int
i =
0
; i < workerPool.length; i++) {
workerPool[i] =
new
WorkerThread(
"Worker-"
+ i,
this
);
}
}
/**
* push switch to start all of worker to work
*/
public
void
startWorker() {
Arrays.asList(workerPool).forEach(WorkerThread::start);
// List<WorkerThread> workerThreads = Arrays.asList(workerPool);
//
// workerThreads.stream().forEach(WorkerThread::start);
}
public
synchronized
void
put(Request request) {
while
(count >= requestQueue.length) {
try
{
this
.wait();
}
catch
(InterruptedException e) {
e.printStackTrace();
}
}
this
.requestQueue[tail] = request;
this
.tail = (tail +
1
) % requestQueue.length;
this
.count++;
this
.notifyAll();
}
public
synchronized
Request take() {
while
(count <=
0
) {
try
{
this
.wait();
}
catch
(InterruptedException e) {
e.printStackTrace();
}
}
Request request =
this
.requestQueue[head];
this
.head = (
this
.head +
1
) %
this
.requestQueue.length;
this
.count--;
this
.notifyAll();
return
request;
}
}
|
Requestqueue可以当做桌子,是一个数量有限的请求队列。threadPool是一个工人线程的数组,这就是一个线程池。在这里提供了putRequest和takeRequest方法,分别是往请求队列放入请求和取出请,这里使用了上一篇博文讲到的生产者消费者模式 java多线程设计模式之消费者生产者模式。确保了WorkerThread和ClientThread之间可以友好合作.
工人线程:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
public
class
WorkerThread
extends
Thread {
private
static
final
Random random =
new
Random(System.currentTimeMillis());
private
final
Channel channel;
public
WorkerThread(String name, Channel channel) {
super
(name);
this
.channel = channel;
}
@Override
public
void
run() {
while
(
true
) {
channel.take().execute();
try
{
Thread.sleep(random.nextInt(1_000));
}
catch
(InterruptedException e) {
e.printStackTrace();
}
}
}
}
|
这里就是一个不断从请求队列中取出请求然后执行请求的过程,保证了工人线程的复用,并不会执行完一个请求任务就销毁.
最后是Main:
1
2
3
4
5
6
7
8
9
10
11
|
public
class
WorkerClient {
public
static
void
main(String[] args) {
final
Channel channel =
new
Channel(
5
);
channel.startWorker();
new
ClientThread(
"Alex"
, channel).start();
new
ClientThread(
"Jack"
, channel).start();
new
ClientThread(
"William"
, channel).start();
}
}
|
结果:
Worker-4 executed Request=> No.0 Name.Alex Worker-2 executed Request=> No.0 Name.Jack Worker-3 executed Request=> No.0 Name.William Worker-4 executed Request=> No.1 Name.Jack Worker-0 executed Request=> No.1 Name.William Worker-3 executed Request=> No.2 Name.Jack Worker-2 executed Request=> No.1 Name.Alex Worker-4 executed Request=> No.2 Name.William Worker-1 executed Request=> No.3 Name.Jack Worker-3 executed Request=> No.2 Name.Alex Worker-4 executed Request=> No.3 Name.William Worker-0 executed Request=> No.4 Name.Jack Worker-0 executed Request=> No.3 Name.Alex Worker-1 executed Request=> No.5 Name.Jack Worker-3 executed Request=> No.4 Name.William Worker-1 executed Request=> No.6 Name.Jack Worker-2 executed Request=> No.4 Name.Alex Worker-3 executed Request=> No.7 Name.Jack Worker-0 executed Request=> No.5 Name.William Worker-1 executed Request=> No.5 Name.Alex Worker-4 executed Request=> No.8 Name.Jack Worker-2 executed Request=> No.6 Name.Alex Worker-0 executed Request=> No.7 Name.Alex Worker-4 executed Request=> No.8 Name.Alex Worker-2 executed Request=> No.6 Name.William 省略... 。
可以看出线程执行任务的线程就是WorkerThread1,2,3,4,5五个,它们不断执行来自ClientThread Alex,Jack,William的请求任务.
到此这篇关于Java多线程之Worker Thread模式的文章就介绍到这了,更多相关Java多线程 Worker Thread内容请搜索我以前的文章或继续浏览下面的相关文章希望大家以后多多支持我! 。
原文链接:https://juejin.cn/post/7023986653987340319 。
最后此篇关于Java多线程之Worker Thread模式的文章就讲到这里了,如果你想了解更多关于Java多线程之Worker Thread模式的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
对此感到疯狂,真的缺少一些东西。 我有webpack 4.6.0,webpack-cli ^ 2.1.2,所以是最新的。 在文档(https://webpack.js.org/concepts/mod
object Host "os.google.com" { import "windows" address = "linux.google.com" groups = ["linux"] } obj
每当我安装我的应用程序时,我都可以将数据库从 Assets 文件夹复制到 /data/data/packagename/databases/ .到此为止,应用程序工作得很好。 但 10 或 15 秒后
我在 cc 模式缓冲区中使用 hideshow.el 来折叠我不查看的文件部分。 如果能够在 XML 文档中做到这一点就好了。我使用 emacs 22.2.1 和内置的 sgml-mode 进行 xm
已结束。此问题不符合 Stack Overflow guidelines .它目前不接受答案。 我们不允许提出有关书籍、工具、软件库等方面的建议的问题。您可以编辑问题,以便用事实和引用来回答它。 关闭
根据java: public Scanner useDelimiter(String pattern) Sets this scanner's delimiting pattern to a patt
我读过一些关于 PRG 模式以及它如何防止用户重新提交表单的文章。比如this post有一张不错的图: 我能理解为什么在收到 2xx 后用户刷新页面时不会发生表单提交。但我仍然想知道: (1) 如果
看看下面的图片,您可能会清楚地看到这一点。 那么如何在带有其他一些 View 的简单屏幕中实现没有任何弹出/对话框/模式的微调器日期选择器? 我在整个网络上进行了谷歌搜索,但没有找到与之相关的任何合适
我不知道该怎么做,我一直遇到问题。 以下是代码: rows = int(input()) for i in range(1,rows): for j in range(1,i+1):
我想为重写创建一个正则表达式。 将所有请求重写为 index.php(不需要匹配),它不是以/api 开头,或者不是以('.html',或'.js'或'.css'或'.png'结束) 我的例子还是这样
MVC模式代表 Model-View-Controller(模型-视图-控制器) 模式 MVC模式用于应用程序的分层开发 Model(模型) - 模型代表一个存取数据的对象或 JAVA PO
我想为组织模式创建一个 RDF 模式世界。您可能知道,组织模式文档基于层次结构大纲,其中标题是主要的分组实体。 * March auxiliary :PROPERTIES: :HLEVEL: 1 :E
我正在编写一个可以从文件中读取 JSON 数据的软件。该文件包含“person”——一个值为对象数组的对象。我打算使用 JSON 模式验证库来验证内容,而不是自己编写代码。符合代表以下数据的 JSON
假设我有 4 张 table 人 公司 团体 和 账单 现在bills/persons和bills/companys和bills/groups之间是多对多的关系。 我看到了 4 种可能的 sql 模式
假设您有这样的文档: doc1: id:1 text: ... references: Journal1, 2013, pag 123 references: Journal2, 2014,
我有这个架构。它检查评论,目前工作正常。 var schema = { id: '', type: 'object', additionalProperties: false, pro
这可能很简单,但有人可以解释为什么以下模式匹配不明智吗?它说其他规则,例如1, 0, _ 永远不会匹配。 let matchTest(n : int) = let ran = new Rand
我有以下选择序列作为 XML 模式的一部分。理想情况下,我想要一个序列: 来自 my:namespace 的元素必须严格解析。 来自任何其他命名空间的元素,不包括 ##targetNamespace和
我希望编写一个 json 模式来涵盖这个(简化的)示例 { "errorMessage": "", "nbRunningQueries": 0, "isError": Fals
首先,我是 f# 的新手,所以也许答案很明显,但我没有看到。所以我有一些带有 id 和值的元组。我知道我正在寻找的 id,我想从我传入的三个元组中选择正确的元组。我打算用两个 match 语句来做到这
我是一名优秀的程序员,十分优秀!