-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsearch.xml
More file actions
182 lines (87 loc) · 81.7 KB
/
search.xml
File metadata and controls
182 lines (87 loc) · 81.7 KB
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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title>使用@Async注解报错提示没有返回值</title>
<link href="/2024/02/10/%E4%BD%BF%E7%94%A8@Async%E6%B3%A8%E8%A7%A3%E6%8A%A5%E9%94%99%E6%8F%90%E7%A4%BA%E6%B2%A1%E6%9C%89%E8%BF%94%E5%9B%9E%E5%80%BC/"/>
<url>/2024/02/10/%E4%BD%BF%E7%94%A8@Async%E6%B3%A8%E8%A7%A3%E6%8A%A5%E9%94%99%E6%8F%90%E7%A4%BA%E6%B2%A1%E6%9C%89%E8%BF%94%E5%9B%9E%E5%80%BC/</url>
<content type="html"><![CDATA[<h2 id="使用-Async注解报错提示没有返回值"><a href="#使用-Async注解报错提示没有返回值" class="headerlink" title="使用@Async注解报错提示没有返回值"></a>使用@Async注解报错提示没有返回值</h2><h4 id="问题描述"><a href="#问题描述" class="headerlink" title="问题描述"></a>问题描述</h4><p>报错信息如下:</p><p><img src="http://www.kdocs.cn/api/v3/office/copy/bFFKUytlZEZkMUhNeGRUSytoQkx5c25XNTNabjVFS3Z6cHhXNkZCRjVMZmEyNnlCU2N3OC9ReDA0WVFGY1VLSGxjcTJ6b3BKWjRhcmMwVTdlc0c1aiszaWprVHNlR2VUb1N6YUdDWmtyZUsxU0Zja3k5TDdvOGZ3Zk5qMncrT3RPczQ4MWtTekZJWDk5RlhCbjIxTVh2MXF5RUpJUkQwQStDbURzU2huUlJnV2I0dk5BSFpDL1hRT3hKMzM3N2FZYWRRN3MxRUF6b0w4aVlNWUdiVU4vbjdKVURwZFcvbklUL2JlVlhZRXJBRmFiaDRHTWtJeFNKWlVOVWZPbmdza0tjK3NsRFI1QzZVPQ==/attach/object/PYZM2BIBOA" alt="img"></p><p>我是代码里用了异步线程,AOP做了一层切面处理,底层是通过jdk动态代理cglib实现。</p><h4 id="解决方案"><a href="#解决方案" class="headerlink" title="解决方案"></a>解决方案</h4><p><img src="http://www.kdocs.cn/api/v3/office/copy/bFFKUytlZEZkMUhNeGRUSytoQkx5c25XNTNabjVFS3Z6cHhXNkZCRjVMZmEyNnlCU2N3OC9ReDA0WVFGY1VLSGxjcTJ6b3BKWjRhcmMwVTdlc0c1aiszaWprVHNlR2VUb1N6YUdDWmtyZUsxU0Zja3k5TDdvOGZ3Zk5qMncrT3RPczQ4MWtTekZJWDk5RlhCbjIxTVh2MXF5RUpJUkQwQStDbURzU2huUlJnV2I0dk5BSFpDL1hRT3hKMzM3N2FZYWRRN3MxRUF6b0w4aVlNWUdiVU4vbjdKVURwZFcvbklUL2JlVlhZRXJBRmFiaDRHTWtJeFNKWlVOVWZPbmdza0tjK3NsRFI1QzZVPQ==/attach/object/EQ2M2BIA5M" alt="img"></p><p>为什么一定要Integer不能用Int类型</p><p>查了一下,如果代理的方法返回值类型为void,就return null;否则就return method.invoke(my, args);</p><p>也就是说,动态代理在没有返回值的情况下,会返回null值。</p><p>我使用的@Asyn就是没有返回值的,所以会返回null</p><p>null值必须用包装类Integer去接收。</p><p>修改前</p><p><img src="http://www.kdocs.cn/api/v3/office/copy/bFFKUytlZEZkMUhNeGRUSytoQkx5c25XNTNabjVFS3Z6cHhXNkZCRjVMZmEyNnlCU2N3OC9ReDA0WVFGY1VLSGxjcTJ6b3BKWjRhcmMwVTdlc0c1aiszaWprVHNlR2VUb1N6YUdDWmtyZUsxU0Zja3k5TDdvOGZ3Zk5qMncrT3RPczQ4MWtTekZJWDk5RlhCbjIxTVh2MXF5RUpJUkQwQStDbURzU2huUlJnV2I0dk5BSFpDL1hRT3hKMzM3N2FZYWRRN3MxRUF6b0w4aVlNWUdiVU4vbjdKVURwZFcvbklUL2JlVlhZRXJBRmFiaDRHTWtJeFNKWlVOVWZPbmdza0tjK3NsRFI1QzZVPQ==/attach/object/Y42M2BIAF4" alt="img"></p><p>修改后</p><p><img src="http://www.kdocs.cn/api/v3/office/copy/bFFKUytlZEZkMUhNeGRUSytoQkx5c25XNTNabjVFS3Z6cHhXNkZCRjVMZmEyNnlCU2N3OC9ReDA0WVFGY1VLSGxjcTJ6b3BKWjRhcmMwVTdlc0c1aiszaWprVHNlR2VUb1N6YUdDWmtyZUsxU0Zja3k5TDdvOGZ3Zk5qMncrT3RPczQ4MWtTekZJWDk5RlhCbjIxTVh2MXF5RUpJUkQwQStDbURzU2huUlJnV2I0dk5BSFpDL1hRT3hKMzM3N2FZYWRRN3MxRUF6b0w4aVlNWUdiVU4vbjdKVURwZFcvbklUL2JlVlhZRXJBRmFiaDRHTWtJeFNKWlVOVWZPbmdza0tjK3NsRFI1QzZVPQ==/attach/object/RE242BIAWU" alt="img"></p><p>参考链接</p><p><a href="https://stackoverflow.com/questions/56497893/org-springframework-aop-aopinvocationexception-null-return-value-from-advice-do">https://stackoverflow.com/questions/56497893/org-springframework-aop-aopinvocationexception-null-return-value-from-advice-do</a></p>]]></content>
<categories>
<category> java </category>
</categories>
<tags>
<tag> java </tag>
</tags>
</entry>
<entry>
<title>记一次RabbitMQ踩坑</title>
<link href="/2024/01/19/%E8%AE%B0%E4%B8%80%E6%AC%A1RabbitMQ%E8%B8%A9%E5%9D%91/"/>
<url>/2024/01/19/%E8%AE%B0%E4%B8%80%E6%AC%A1RabbitMQ%E8%B8%A9%E5%9D%91/</url>
<content type="html"><![CDATA[<h3 id="记一次RabbitMQ踩坑"><a href="#记一次RabbitMQ踩坑" class="headerlink" title="记一次RabbitMQ踩坑"></a>记一次RabbitMQ踩坑</h3><h4 id="1-问题描述"><a href="#1-问题描述" class="headerlink" title="1. 问题描述"></a>1. 问题描述</h4><p>前段时间写消费端代码的时候遇到个mq确认机制的问题,消费端接收消息消费的过程,如果发生异常并且没有被捕获,这个时候会抛到源码层面去catch异常,由于rabbitmq有消息ack确认机制,消费端因为发生异常没有被捕获导致一直回不了ack,所以会一直重复消费某条消息。</p><h4 id="2-错误案例"><a href="#2-错误案例" class="headerlink" title="2. 错误案例"></a>2. 错误案例</h4><p>消费端代码如下:</p><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token annotation punctuation">@RabbitHandler</span><span class="token annotation punctuation">@SneakyThrows</span><span class="token annotation punctuation">@RabbitListener</span><span class="token punctuation">(</span>queues <span class="token operator">=</span> <span class="token string">"${spring.rabbitmq.first.queue}"</span><span class="token punctuation">,</span> containerFactory <span class="token operator">=</span> <span class="token string">"firstFactory"</span><span class="token punctuation">)</span><span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">onMessageOne</span><span class="token punctuation">(</span><span class="token class-name">Message</span> message<span class="token punctuation">,</span> <span class="token class-name">Channel</span> channel<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token class-name">String</span> msg <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">String</span><span class="token punctuation">(</span>message<span class="token punctuation">.</span><span class="token function">getBody</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token constant">ENCODING</span><span class="token punctuation">)</span><span class="token punctuation">;</span> log<span class="token punctuation">.</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token string">"[RabbitListener 监听的消息-ONE] - [{}]"</span><span class="token punctuation">,</span> msg<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token class-name">JSONObject</span> jsonObject <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">JSONObject</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> jsonObject<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span><span class="token string">"queue"</span><span class="token punctuation">,</span> firstQueue<span class="token punctuation">)</span><span class="token punctuation">;</span> jsonObject<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span><span class="token string">"message"</span><span class="token punctuation">,</span> msg<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//此处代码出现异常,并未被捕获</span> <span class="token class-name">ServiceMQInvoke</span> invokeGroovy <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token class-name">ServiceMQInvoke</span><span class="token punctuation">)</span> groovyProcess<span class="token punctuation">.</span><span class="token function">getGroovyClass</span><span class="token punctuation">(</span>groovyUrl<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">newInstance</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> invokeGroovy<span class="token punctuation">.</span><span class="token function">consumer</span><span class="token punctuation">(</span>eliteBean<span class="token punctuation">,</span> jsonObject<span class="token punctuation">)</span><span class="token punctuation">;</span> channel<span class="token punctuation">.</span><span class="token function">basicAck</span><span class="token punctuation">(</span>message<span class="token punctuation">.</span><span class="token function">getMessageProperties</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getDeliveryTag</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>由于在执行channel.basicAck()方法前出现了异常,RabbitMQ没有收到ack确认机制,所以会出现消费重复消息的情况。如下图</p><p></p><p>打印三条日志后,就结束了。为什么只打印三条?是因为rabbitmq 有重试机制。配置如下:</p><pre class="line-numbers language-yaml" data-language="yaml"><code class="language-yaml"><span class="token comment">#RabbitMQ配置</span><span class="token key atrule">rabbitmq</span><span class="token punctuation">:</span> <span class="token key atrule">listener</span><span class="token punctuation">:</span> <span class="token key atrule">simple</span><span class="token punctuation">:</span> <span class="token key atrule">acknowledge-mode</span><span class="token punctuation">:</span> manual <span class="token comment">#手动 ack</span> <span class="token key atrule">default-requeue-rejected</span><span class="token punctuation">:</span> <span class="token boolean important">true</span> <span class="token key atrule">retry</span><span class="token punctuation">:</span> <span class="token key atrule">enabled</span><span class="token punctuation">:</span> <span class="token boolean important">true</span> <span class="token key atrule">max-attempts</span><span class="token punctuation">:</span> <span class="token number">3</span> <span class="token comment">#重试3次</span> <span class="token key atrule">direct</span><span class="token punctuation">:</span> <span class="token key atrule">acknowledge-mode</span><span class="token punctuation">:</span> manual <span class="token key atrule">retry</span><span class="token punctuation">:</span> <span class="token key atrule">enabled</span><span class="token punctuation">:</span> <span class="token boolean important">true</span> <span class="token key atrule">max-attempts</span><span class="token punctuation">:</span> <span class="token number">3</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>是因为max-attempts参数配置重试次数为3。</p><h4 id="3-正确案例"><a href="#3-正确案例" class="headerlink" title="3. 正确案例"></a>3. 正确案例</h4><p>加上try catch捕获异常,让程序出现异常后继续往下执行。代码如下:</p><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token annotation punctuation">@RabbitHandler</span><span class="token annotation punctuation">@SneakyThrows</span><span class="token annotation punctuation">@RabbitListener</span><span class="token punctuation">(</span>queues <span class="token operator">=</span> <span class="token string">"${spring.rabbitmq.first.queue}"</span><span class="token punctuation">,</span> containerFactory <span class="token operator">=</span> <span class="token string">"firstFactory"</span><span class="token punctuation">)</span><span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">onMessageOne</span><span class="token punctuation">(</span><span class="token class-name">Message</span> message<span class="token punctuation">,</span> <span class="token class-name">Channel</span> channel<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token class-name">String</span> msg <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">String</span><span class="token punctuation">(</span>message<span class="token punctuation">.</span><span class="token function">getBody</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token constant">ENCODING</span><span class="token punctuation">)</span><span class="token punctuation">;</span> log<span class="token punctuation">.</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token string">"[RabbitListener 监听的消息-ONE] - [{}]"</span><span class="token punctuation">,</span> msg<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">try</span> <span class="token punctuation">{</span> <span class="token class-name">JSONObject</span> jsonObject <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">JSONObject</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> jsonObject<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span><span class="token string">"queue"</span><span class="token punctuation">,</span> firstQueue<span class="token punctuation">)</span><span class="token punctuation">;</span> jsonObject<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span><span class="token string">"message"</span><span class="token punctuation">,</span> msg<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token class-name">ServiceMQInvoke</span> invokeGroovy <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token class-name">ServiceMQInvoke</span><span class="token punctuation">)</span> groovyProcess<span class="token punctuation">.</span><span class="token function">getGroovyClass</span><span class="token punctuation">(</span>groovyUrl<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">newInstance</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> invokeGroovy<span class="token punctuation">.</span><span class="token function">consumer</span><span class="token punctuation">(</span>eliteBean<span class="token punctuation">,</span> jsonObject<span class="token punctuation">)</span><span class="token punctuation">;</span> channel<span class="token punctuation">.</span><span class="token function">basicAck</span><span class="token punctuation">(</span>message<span class="token punctuation">.</span><span class="token function">getMessageProperties</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getDeliveryTag</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span> log<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">"[RabbitListener 监听的消息异常-ONE] - [{}]"</span><span class="token punctuation">,</span> e<span class="token punctuation">.</span><span class="token function">getMessage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>加了异常捕获后消息能正常消费了。</p>]]></content>
<categories>
<category> rabbitMQ </category>
</categories>
<tags>
<tag> java </tag>
</tags>
</entry>
<entry>
<title>记一次sql字符排序规则不统一导致的报错</title>
<link href="/2023/11/14/%E8%AE%B0%E4%B8%80%E6%AC%A1sql%E5%AD%97%E7%AC%A6%E6%8E%92%E5%BA%8F%E8%A7%84%E5%88%99%E4%B8%8D%E7%BB%9F%E4%B8%80%E5%AF%BC%E8%87%B4%E7%9A%84%E6%8A%A5%E9%94%99/"/>
<url>/2023/11/14/%E8%AE%B0%E4%B8%80%E6%AC%A1sql%E5%AD%97%E7%AC%A6%E6%8E%92%E5%BA%8F%E8%A7%84%E5%88%99%E4%B8%8D%E7%BB%9F%E4%B8%80%E5%AF%BC%E8%87%B4%E7%9A%84%E6%8A%A5%E9%94%99/</url>
<content type="html"><![CDATA[<h2 id="记一次sql字符排序规则不统一导致的报错"><a href="#记一次sql字符排序规则不统一导致的报错" class="headerlink" title="记一次sql字符排序规则不统一导致的报错"></a>记一次sql字符排序规则不统一导致的报错</h2><h3 id="问题"><a href="#问题" class="headerlink" title="问题"></a>问题</h3><p>left join表会出现 Illegal mix of collations (utf8_general_ci,IMPLICIT) and (utf8_croatian_ci,IMPLICIT) for operation ‘=’错误.</p><p>这是由于表的编码格式不一致 例如 某个表的排序规则字符编码为utf8_general_ci而关联表的排序规则字符编码为utf8_croatian_ci导致当前错误!</p><p>排查问题发现,只要涉及到作为关联条件的字段都要统一字符编码,要么都设置为一样的编码,要么都设置。出现上面的问题是因为a表中的关联字段设置了字符编码,b表这的关联字段未设置字符编码。关联查询也会报错。</p><h3 id="解决方案"><a href="#解决方案" class="headerlink" title="解决方案"></a>解决方案</h3><ol><li>修改表中字段的字符编码</li></ol><pre class="line-numbers language-sql" data-language="sql"><code class="language-sql">ALTERTABLE 表名 CONVERTTOCHARACTERSET utf8mb4 <span class="token keyword">COLLATE</span> utf8_general_ci<span class="token punctuation">;</span> <span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><ol><li>删除掉字段后面的字符编码</li></ol><pre class="line-numbers language-sql" data-language="sql"><code class="language-sql">ALTERTABLE 表名 DEFAULTCHARACTERSET utf8mb4 <span class="token keyword">COLLATE</span> utf8_general_ci<span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><ol><li>删除每个字段后面的字符编码</li></ol><p>最终采用了第三种方案,为了适配以后各个项目数据库设置的编码不一样问题,如果不设置字段后面的字符编码会默认采用数据库的字符编码。避免了以后出现同样的问题。</p>]]></content>
<categories>
<category> 数据库 </category>
</categories>
<tags>
<tag> sql </tag>
</tags>
</entry>
<entry>
<title>TransmittableThreadLocal 的使用指南</title>
<link href="/2023/10/16/TransmittableThreadLocal-%E7%9A%84%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%97/"/>
<url>/2023/10/16/TransmittableThreadLocal-%E7%9A%84%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%97/</url>
<content type="html"><![CDATA[<h1 id="TransmittableThreadLocal-的使用指南"><a href="#TransmittableThreadLocal-的使用指南" class="headerlink" title="TransmittableThreadLocal 的使用指南"></a>TransmittableThreadLocal 的使用指南</h1><h2 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h2><p><code>TransmittableThreadLocal</code> 是一种用于多线程环境下的数据传递的工具。它是 <code>ThreadLocal</code> 的增强版本,能够在不同线程之间有效传递数据,尤其适用于线程池、异步任务等场景。</p><h2 id="如何使用-TransmittableThreadLocal"><a href="#如何使用-TransmittableThreadLocal" class="headerlink" title="如何使用 TransmittableThreadLocal"></a>如何使用 TransmittableThreadLocal</h2><h3 id="1-引入依赖"><a href="#1-引入依赖" class="headerlink" title="1. 引入依赖"></a>1. 引入依赖</h3><p>项目中引入了 <code>TransmittableThreadLocal</code> 相关的依赖。可以使用阿里巴巴的 Transmittable-Thread-Local,具体依赖可以在 Maven 中配置:</p><p>Maven:</p><pre class="line-numbers language-markup" data-language="markup"><code class="language-markup"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>dependency</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>groupId</span><span class="token punctuation">></span></span>com.alibaba<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>groupId</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>artifactId</span><span class="token punctuation">></span></span>transmittable-thread-local<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>artifactId</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>version</span><span class="token punctuation">></span></span>2.14.1<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>version</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>dependency</span><span class="token punctuation">></span></span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span></span></code></pre><h3 id="2-创建-TransmittableThreadLocal-变量"><a href="#2-创建-TransmittableThreadLocal-变量" class="headerlink" title="2. 创建 TransmittableThreadLocal 变量"></a>2. 创建 TransmittableThreadLocal 变量</h3><p>在你的 Java 代码中,创建 <code>TransmittableThreadLocal</code> 类型的变量,定义需要在线程间传递的数据类型。</p><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">import</span> <span class="token import"><span class="token namespace">com<span class="token punctuation">.</span>alibaba<span class="token punctuation">.</span>ttl<span class="token punctuation">.</span></span><span class="token class-name">TransmittableThreadLocal</span></span><span class="token punctuation">;</span><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">SecurityContextHolder</span> <span class="token punctuation">{</span> <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token class-name">TransmittableThreadLocal</span><span class="token generics"><span class="token punctuation"><</span><span class="token class-name">Map</span><span class="token punctuation"><</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">Object</span><span class="token punctuation">></span><span class="token punctuation">></span></span> <span class="token constant">THREAD_LOCAL</span> <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">TransmittableThreadLocal</span><span class="token generics"><span class="token punctuation"><</span><span class="token punctuation">></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">set</span><span class="token punctuation">(</span><span class="token class-name">String</span> key<span class="token punctuation">,</span> <span class="token class-name">Object</span> value<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token class-name">Map</span><span class="token generics"><span class="token punctuation"><</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">Object</span><span class="token punctuation">></span></span> map <span class="token operator">=</span> <span class="token function">getLocalMap</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> map<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span>key<span class="token punctuation">,</span> value <span class="token operator">==</span> <span class="token keyword">null</span> <span class="token operator">?</span> <span class="token class-name">StringUtils</span><span class="token punctuation">.</span><span class="token constant">EMPTY</span> <span class="token operator">:</span> value<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">remove</span><span class="token punctuation">(</span><span class="token class-name">String</span> key<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token class-name">Map</span><span class="token generics"><span class="token punctuation"><</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">Object</span><span class="token punctuation">></span></span> map <span class="token operator">=</span> <span class="token function">getLocalMap</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> map<span class="token punctuation">.</span><span class="token function">remove</span><span class="token punctuation">(</span>key<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token class-name">String</span> <span class="token function">get</span><span class="token punctuation">(</span><span class="token class-name">String</span> key<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token class-name">Map</span><span class="token generics"><span class="token punctuation"><</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">Object</span><span class="token punctuation">></span></span> map <span class="token operator">=</span> <span class="token function">getLocalMap</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token class-name">Convert</span><span class="token punctuation">.</span><span class="token function">toStr</span><span class="token punctuation">(</span>map<span class="token punctuation">.</span><span class="token function">getOrDefault</span><span class="token punctuation">(</span>key<span class="token punctuation">,</span> <span class="token class-name">StringUtils</span><span class="token punctuation">.</span><span class="token constant">EMPTY</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token generics"><span class="token punctuation"><</span><span class="token class-name">T</span><span class="token punctuation">></span></span> <span class="token class-name">T</span> <span class="token function">get</span><span class="token punctuation">(</span><span class="token class-name">String</span> key<span class="token punctuation">,</span> <span class="token class-name">Class</span><span class="token generics"><span class="token punctuation"><</span><span class="token class-name">T</span><span class="token punctuation">></span></span> clazz<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token class-name">Map</span><span class="token generics"><span class="token punctuation"><</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">Object</span><span class="token punctuation">></span></span> map <span class="token operator">=</span> <span class="token function">getLocalMap</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token class-name">StringUtils</span><span class="token punctuation">.</span><span class="token function">cast</span><span class="token punctuation">(</span>map<span class="token punctuation">.</span><span class="token function">getOrDefault</span><span class="token punctuation">(</span>key<span class="token punctuation">,</span> <span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token class-name">Map</span><span class="token generics"><span class="token punctuation"><</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">Object</span><span class="token punctuation">></span></span> <span class="token function">getLocalMap</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token class-name">Map</span><span class="token generics"><span class="token punctuation"><</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">Object</span><span class="token punctuation">></span></span> map <span class="token operator">=</span> <span class="token constant">THREAD_LOCAL</span><span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>map <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> map <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ConcurrentHashMap</span><span class="token generics"><span class="token punctuation"><</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">Object</span><span class="token punctuation">></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token constant">THREAD_LOCAL</span><span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span>map<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> map<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h3 id="3-设置和获取数据"><a href="#3-设置和获取数据" class="headerlink" title="3. 设置和获取数据"></a>3. 设置和获取数据</h3><p>在你的应用程序中,你可以使用 <code>TransmittableThreadLocal</code> 来设置和获取数据。例如,将当前登录的用户信息放在ThreadLocal中:</p><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token class-name">SecurityContextHolder</span><span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span><span class="token class-name">SecurityConstants<span class="token punctuation">.</span>Details</span><span class="token punctuation">.</span><span class="token constant">LOGIN_USER</span><span class="token punctuation">.</span><span class="token function">getCode</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token class-name">JSONObject</span><span class="token punctuation">.</span><span class="token function">parseObject</span><span class="token punctuation">(</span>loginUserStr<span class="token punctuation">,</span> <span class="token class-name">LoginUser</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><p>然后在另一个线程中,你可以获取该数据:</p><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token class-name">String</span> user <span class="token operator">=</span> <span class="token class-name">SecurityContextHolder</span><span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token class-name">SecurityConstants<span class="token punctuation">.</span>Details</span><span class="token punctuation">.</span><span class="token constant">LOGIN_USER</span><span class="token punctuation">.</span><span class="token function">getCode</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><h2 id="注意事项"><a href="#注意事项" class="headerlink" title="注意事项"></a>注意事项</h2><p>使用 <code>TransmittableThreadLocal</code> 时需要注意以下事项:</p><ol><li><p><strong>依赖包版本</strong>:确保你的项目使用了兼容版本的 <code>TransmittableThreadLocal</code> 依赖。通常,你应该使用最新版本以获取最新功能和修复。</p></li><li><p><strong>线程池和异步任务</strong>:主要用途是支持在线程池和异步任务中传递数据,确保你的线程池配置和异步任务调用兼容 <code>TransmittableThreadLocal</code>。</p></li><li><p><strong>清理数据</strong>:一定要在不再需要数据时及时清理,以避免内存泄漏。</p></li><li><p><strong>线程安全性</strong>:<code>TransmittableThreadLocal</code> 本身是线程安全的,但要确保你存储在其中的数据是线程安全的,以避免并发问题。</p></li><li><p><strong>性能影响</strong>:尽管 <code>TransmittableThreadLocal</code> 是为了解决线程池和异步任务中的问题而设计的,但在一般多线程应用中使用时,可能会带来轻微的性能开销。请根据应用需求进行权衡。</p></li></ol><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p><code>TransmittableThreadLocal</code> 是一个用于多线程环境下数据传递的有用工具,特别适用于线程池和异步任务。通过引入依赖,创建变量,设置和获取数据,以及及时清理数据,你可以在多线程应用中安全地传递上下文数据。</p><h2 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h2><ul><li><a href="https://github.com/alibaba/transmittable-thread-local">Transmittable-Thread-Local GitHub</a></li><li><a href="https://github.com/alibaba/transmittable-thread-local/wiki">阿里巴巴 Transmittable-Thread-Local 文档</a></li></ul>]]></content>
<categories>
<category> java </category>
</categories>
<tags>
<tag> 多线程 </tag>
</tags>
</entry>
<entry>
<title>CountDownLatch和Future用法</title>
<link href="/2023/08/30/CountDownLatch%E5%92%8CFuture%E7%94%A8%E6%B3%95/"/>
<url>/2023/08/30/CountDownLatch%E5%92%8CFuture%E7%94%A8%E6%B3%95/</url>
<content type="html"><![CDATA[<h2 id="1-CountDownLatch-概念"><a href="#1-CountDownLatch-概念" class="headerlink" title="1. CountDownLatch 概念"></a><strong>1. CountDownLatch 概念</strong></h2><p><code>CountDownLatch</code> 可以用于控制线程的同步等待。<code>CountDownLatch</code> 通常用于一个或多个线程等待其他线程的操作完成后再继续执行。</p><p><code>CountDownLatch</code> 可以用于很多场景,例如等待多个子任务完成后再执行主任务,控制并发测试中的线程同步,或者等待多个服务初始化完成后再启动应用程序等。</p><p>CountDownLatch 定义了一个<strong>计数器</strong>,和一个<strong>阻塞队列</strong>, 当计数器的值递减为0之前,阻塞队列里面的线程处于挂起状态,直到所有线程执行完毕。</p><p><strong>要点</strong>:</p><ol><li>初始化计数:<code>CountDownLatch</code> 的实例通过指定一个初始计数来初始化,该计数表示需要等待的线程数量。</li><li>线程等待:线程可以通过 <code>await()</code> 方法来等待计数器归零。当调用 <code>await()</code> 方法时,如果计数器不为零,则线程将进入等待状态,直到计数器变为零。</li><li>计数减少:通过 <code>countDown()</code> 方法可以将计数器减少1。每次调用 <code>countDown()</code> 方法都会使计数器减少1,直到计数器达到零。</li><li>等待阻塞:<code>await()</code> 方法调用后,当前线程会被阻塞,直到满足以下任一条件:计数器归零,或者当前线程被中断。</li><li>倒计时完成后:当计数器归零时,所有被阻塞的线程将被释放,可以继续执行后续操作。</li></ol><p><strong>示例代码:</strong></p><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">CountDownLatchDemo</span> <span class="token punctuation">{</span> <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token class-name">Map</span> map <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">HashMap</span><span class="token generics"><span class="token punctuation"><</span><span class="token punctuation">></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token class-name">CountDownLatch</span> countDownLatch <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">CountDownLatch</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">//记录开始时间</span> <span class="token keyword">long</span> start <span class="token operator">=</span> <span class="token class-name">System</span><span class="token punctuation">.</span><span class="token function">currentTimeMillis</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token class-name">Thread</span> thread1 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Thread</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">Runnable</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token annotation punctuation">@Override</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">run</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">try</span> <span class="token punctuation">{</span> <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"线程1任务开始执行"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">sleep</span><span class="token punctuation">(</span><span class="token number">6000</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//任务执行需要6秒</span> map<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span><span class="token string">"thread1"</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//保存结果值</span> countDownLatch<span class="token punctuation">.</span><span class="token function">countDown</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//标记已经完成一个任务</span> <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"线程1任务执行完毕"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">InterruptedException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span> e<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> thread1<span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token class-name">Thread</span> thread2 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Thread</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">Runnable</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token annotation punctuation">@Override</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">run</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">try</span> <span class="token punctuation">{</span> <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"线程2任务开始执行"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">sleep</span><span class="token punctuation">(</span><span class="token number">3000</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//任务执行需要3秒</span> map<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span><span class="token string">"thread2"</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//保存结果值</span> countDownLatch<span class="token punctuation">.</span><span class="token function">countDown</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//标记已经完成一个任务</span> <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"线程2任务执行完毕"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">InterruptedException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span> e<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> thread2<span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">try</span> <span class="token punctuation">{</span> countDownLatch<span class="token punctuation">.</span><span class="token function">await</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//等待所有任务执行完毕</span> <span class="token keyword">long</span> endTime <span class="token operator">=</span> <span class="token class-name">System</span><span class="token punctuation">.</span><span class="token function">currentTimeMillis</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//记录结束时间</span> <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"------统计所有线程全部完成--------"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"统计结果为:"</span> <span class="token operator">+</span> map<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"任务总执行时间为"</span> <span class="token operator">+</span> <span class="token punctuation">(</span>endTime <span class="token operator">-</span> start<span class="token punctuation">)</span> <span class="token operator">/</span> <span class="token number">1000</span> <span class="token operator">+</span> <span class="token string">"秒"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span> e<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>输出结果:</p><pre class="line-numbers language-java" data-language="java"><code class="language-java">线程<span class="token number">1</span>任务开始执行线程<span class="token number">2</span>任务开始执行线程<span class="token number">2</span>任务执行完毕线程<span class="token number">1</span>任务执行完毕<span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span>统计所有线程全部完成<span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span>统计结果为:<span class="token punctuation">{</span>thread1<span class="token operator">=</span><span class="token number">1</span><span class="token punctuation">,</span> thread2<span class="token operator">=</span><span class="token number">2</span><span class="token punctuation">}</span>任务总执行时间为<span class="token number">6</span>秒<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h3 id="1-1-源码分析"><a href="#1-1-源码分析" class="headerlink" title="1.1 源码分析"></a>1.1 源码分析</h3><h4 id="1-1-1-创建计数器"><a href="#1-1-1-创建计数器" class="headerlink" title="1.1.1 创建计数器"></a>1.1.1 创建计数器</h4><p>当我们调用CountDownLatch countDownLatch=new CountDownLatch(2) 时候,此时会创建一个AQS的同步队列,并把创建CountDownLatch 传进来的计数器赋值给AQS队列的 state,所以state的值也代表CountDownLatch所剩余的计数次数;</p><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">public</span> <span class="token class-name">CountDownLatch</span><span class="token punctuation">(</span><span class="token keyword">int</span> count<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>count <span class="token operator"><</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">IllegalArgumentException</span><span class="token punctuation">(</span><span class="token string">"count < 0"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>sync <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Sync</span><span class="token punctuation">(</span>count<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//创建同步队列,并设置初始计数器值</span> <span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre><h4 id="1-1-2-countDown-方法"><a href="#1-1-2-countDown-方法" class="headerlink" title="1.1.2 countDown()方法"></a>1.1.2 countDown()方法</h4><p>调用 countDownLatch.countDown()方法,会对计数器进行减一,AQS(阻塞队列)内部是通过释放锁的方式,对state进行减1操作,当state=0的时候证明计数器已经递减完毕,此时会将AQS阻塞队列里的节点线程全部唤醒。</p><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">countDown</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">this</span><span class="token punctuation">.</span>sync<span class="token punctuation">.</span><span class="token function">releaseShared</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//Sync extends AbstractQueuedSynchronizer </span><span class="token punctuation">}</span><span class="token keyword">public</span> <span class="token keyword">final</span> <span class="token keyword">boolean</span> <span class="token function">releaseShared</span><span class="token punctuation">(</span><span class="token keyword">int</span> var1<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">tryReleaseShared</span><span class="token punctuation">(</span>var1<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token comment">//当计数器为0时,</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">doReleaseShared</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//唤醒线程</span> <span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h2 id="2-线程池使用Future-get"><a href="#2-线程池使用Future-get" class="headerlink" title="2. 线程池使用Future.get()"></a>2. 线程池使用Future.get()</h2><p><code>Future</code> 它表示一个异步计算的结果。通过 <code>Future</code> 接口,我们可以提交任务给线程池进行异步执行,并在未来某个时间获取任务的执行结果。</p><p>future的核心思想是异步调用,当我们需要调用一个函数方法时,如果这个函数执行得很慢,那么我们就要进行等待。因此,我们可以让被调者立即返回,让它在后台慢慢处理这个请求。对于调用者来说,则可以先处理一些其他任务,在真正需要数据的场合再去尝试获得需要的数据。</p><p><strong>要点:</strong></p><ol><li>提交任务:通过将任务提交给线程池的执行器(<code>Executor</code>)的 <code>submit()</code> 或 <code>submit(Callable)</code> 方法,可以获得一个 <code>Future</code> 对象来表示任务的执行。</li><li>异步执行:任务被线程池接受后,线程池会在后台使用一个线程或线程池中的多个线程来执行任务。任务的执行不会阻塞当前线程,可以继续进行其他操作。</li><li>获取结果:通过调用 <code>Future</code> 对象的 <code>get()</code> 方法,可以阻塞当前线程,直到任务执行完成并返回结果。<code>get()</code> 方法会返回任务的执行结果,如果任务还没有完成,则会阻塞等待。</li><li>取消任务:可以通过调用 <code>Future</code> 对象的 <code>cancel(boolean)</code> 方法来取消任务的执行。传递参数为 <code>true</code> 表示尝试取消正在执行的任务,传递参数为 <code>false</code> 表示不尝试取消正在执行的任务。</li><li>判断任务状态:可以通过调用 <code>isDone()</code> 方法来判断任务是否已经完成,或通过 <code>isCancelled()</code> 方法判断任务是否被取消。</li><li>阻塞超时:<code>get()</code> 方法还支持设置阻塞超时时间,如果任务在指定的时间内没有完成,则抛出超时异常。</li></ol><p><strong>示例代码</strong></p><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">FutureDemo</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// 初始化线程池</span> <span class="token class-name">ExecutorService</span> threadPool <span class="token operator">=</span> <span class="token class-name">Executors</span><span class="token punctuation">.</span><span class="token function">newFixedThreadPool</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 初始化线程任务</span> <span class="token class-name">MyTask</span> myTask <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">MyTask</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token class-name">MyTask2</span> myTask2 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">MyTask2</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 向线程池递交线程任务</span> <span class="token class-name">Future</span><span class="token generics"><span class="token punctuation"><</span><span class="token class-name">Integer</span><span class="token punctuation">></span></span> future <span class="token operator">=</span> threadPool<span class="token punctuation">.</span><span class="token function">submit</span><span class="token punctuation">(</span>myTask<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token class-name">Future</span><span class="token generics"><span class="token punctuation"><</span><span class="token class-name">Integer</span><span class="token punctuation">></span></span> future2 <span class="token operator">=</span> threadPool<span class="token punctuation">.</span><span class="token function">submit</span><span class="token punctuation">(</span>myTask2<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 主线程休眠5秒,模拟主线程在做其他的事情</span> <span class="token keyword">try</span> <span class="token punctuation">{</span> <span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">sleep</span><span class="token punctuation">(</span><span class="token number">5000</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">InterruptedException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span> e<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">// 主线程获取异步任务的执行结果</span> <span class="token keyword">try</span> <span class="token punctuation">{</span> <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"异步线程任务执行结果1 "</span> <span class="token operator">+</span> future<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"检查异步线程任务是否执行完毕1 "</span> <span class="token operator">+</span> future<span class="token punctuation">.</span><span class="token function">isDone</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"异步线程任务执行结果2 "</span> <span class="token operator">+</span> future2<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"检查异步线程任务是否执行完毕2 "</span> <span class="token operator">+</span> future2<span class="token punctuation">.</span><span class="token function">isDone</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">InterruptedException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span> e<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">ExecutionException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span> e<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token comment">// 静态内部类,实现Callable接口的任务类</span> <span class="token keyword">static</span> <span class="token keyword">class</span> <span class="token class-name">MyTask</span> <span class="token keyword">implements</span> <span class="token class-name">Callable</span><span class="token generics"><span class="token punctuation"><</span><span class="token class-name">Integer</span><span class="token punctuation">></span></span> <span class="token punctuation">{</span> <span class="token keyword">private</span> <span class="token keyword">int</span> num<span class="token punctuation">;</span> <span class="token keyword">public</span> <span class="token class-name">MyTask</span><span class="token punctuation">(</span><span class="token keyword">int</span> num<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">this</span><span class="token punctuation">.</span>num <span class="token operator">=</span> num<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token annotation punctuation">@Override</span> <span class="token keyword">public</span> <span class="token class-name">Integer</span> <span class="token function">call</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">Exception</span> <span class="token punctuation">{</span> <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">currentThread</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">" 正在执行异步任务"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>num <span class="token operator">+=</span> <span class="token number">1</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>num<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">static</span> <span class="token keyword">class</span> <span class="token class-name">MyTask2</span> <span class="token keyword">implements</span> <span class="token class-name">Callable</span><span class="token generics"><span class="token punctuation"><</span><span class="token class-name">Integer</span><span class="token punctuation">></span></span> <span class="token punctuation">{</span> <span class="token keyword">private</span> <span class="token keyword">int</span> num<span class="token punctuation">;</span> <span class="token keyword">public</span> <span class="token class-name">MyTask2</span><span class="token punctuation">(</span><span class="token keyword">int</span> num<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">this</span><span class="token punctuation">.</span>num <span class="token operator">=</span> num<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token annotation punctuation">@Override</span> <span class="token keyword">public</span> <span class="token class-name">Integer</span> <span class="token function">call</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">Exception</span> <span class="token punctuation">{</span> <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">currentThread</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">" 正在执行异步任务"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>num <span class="token operator">*=</span> <span class="token number">2</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>num<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p><strong>输出结果</strong></p><pre class="line-numbers language-java" data-language="java"><code class="language-java">pool<span class="token operator">-</span><span class="token number">1</span><span class="token operator">-</span>thread<span class="token operator">-</span><span class="token number">1</span> 正在执行异步任务pool<span class="token operator">-</span><span class="token number">1</span><span class="token operator">-</span>thread<span class="token operator">-</span><span class="token number">2</span> 正在执行异步任务异步线程任务执行结果<span class="token number">1</span> <span class="token number">6</span>检查异步线程任务是否执行完毕<span class="token number">1</span> <span class="token boolean">true</span>异步线程任务执行结果<span class="token number">2</span> <span class="token number">10</span>检查异步线程任务是否执行完毕<span class="token number">2</span> <span class="token boolean">true</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>]]></content>
<categories>
<category> 多线程 </category>
</categories>
<tags>
<tag> java </tag>
</tags>
</entry>
<entry>
<title>HEXO常用命令</title>
<link href="/2023/08/29/HEXO%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4/"/>
<url>/2023/08/29/HEXO%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4/</url>
<content type="html"><![CDATA[<h3 id="常用命令"><a href="#常用命令" class="headerlink" title="常用命令"></a>常用命令</h3><table><thead><tr><th>命令</th><th>描述</th></tr></thead><tbody><tr><td>hexo new post “title”</td><td>新建文章</td></tr><tr><td>hexo new page “title”</td><td>新建页面</td></tr><tr><td>hexo generate/g</td><td>生成静态页面至public目录</td></tr><tr><td>hexo server/s</td><td>开启本地预览访问端口</td></tr><tr><td>hexo deploy/d</td><td>将.deploy目录部署到GitHub</td></tr><tr><td>hexo clean</td><td>清除缓存文件等</td></tr></tbody></table>]]></content>
<categories>
<category> 默认 </category>
</categories>
<tags>
<tag> 默认 </tag>
</tags>
</entry>
<entry>
<title>Spring中的@ConditionalOnExpression注解</title>
<link href="/2023/07/26/Spring%E4%B8%AD%E7%9A%84@ConditionalOnExpression%E6%B3%A8%E8%A7%A3/"/>
<url>/2023/07/26/Spring%E4%B8%AD%E7%9A%84@ConditionalOnExpression%E6%B3%A8%E8%A7%A3/</url>
<content type="html"><![CDATA[<h2 id="ConditionalOnExpression"><a href="#ConditionalOnExpression" class="headerlink" title="@ConditionalOnExpression"></a>@ConditionalOnExpression</h2><p><code>@ConditionalOnExpression</code> 是 Spring提供的一个条件注解。</p><p>该注解用于根据指定的条件表达式来决定是否启用或禁用一个 Spring 组件。</p><h2 id="使用示例"><a href="#使用示例" class="headerlink" title="使用示例"></a>使用示例</h2><p>在配置类、Bean 方法或自定义注解上标记 <code>@ConditionalOnExpression</code> 注解,以基于特定条件来决定是否创建或装配相关的 Bean。</p><p>示例代码:</p><pre class="line-numbers language-none"><code class="language-none">@Configurationpublic class MyConfiguration { @Bean @ConditionalOnExpression("${config.face.enabled:true}") public MyBean myBean() { return new MyBean(); }}<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>在上述示例中,<code>@ConditionalOnExpression("${config.face.enabled:true}")</code> 表示当条件表达式 <code>${config.face.enabled:true}</code> 的结果为真时,才会创建并注册名为 <code>myBean</code> 的 Bean。</p><p>配置文件:</p><pre class="line-numbers language-none"><code class="language-none">config: face: enabled: true<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre><p><code>${config.face.enabled:true}</code> 是一个条件表达式,它可以是任意的 SpEL(Spring Expression Language)表达式。在这个表达式中,<code>${config.face.enabled}</code> 是一个占位符,表示从配置文件<code>ymal</code>获取一个属性值,如果该属性不存在,则使用默认值 <code>true</code>。</p><p>通过使用 <code>@ConditionalOnExpression</code> 注解,可以根据条件表达式动态控制 Bean 的创建和装配。这使得应用在不同的环境或配置下具有灵活的行为。</p><p>需要注意的是,条件表达式的结果类型必须为布尔值。如果条件表达式的结果为 <code>true</code>,则相应的 Bean 将被创建和装配;如果结果为 <code>false</code>,则该 Bean 将被忽略。</p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p><code>@ConditionalOnExpression</code> 注解是一个在 Spring中非常有用的条件注解之一。它使得根据特定条件来控制组件的创建和装配成为可能。通过编写条件表达式,并将其与 <code>@ConditionalOnExpression</code> 注解结合使用,可以在应用程序中实现更灵活的配置和条件性的行为。</p>]]></content>
<categories>
<category> Spring </category>
</categories>
<tags>
<tag> java </tag>
</tags>
</entry>
</search>