java线程实践与总结
# 学习教程
- http://ifeve.com/java-concurrency-thread-directory/ (opens new window)
- http://tutorials.jenkov.com/java-util-concurrent/index.html (opens new window)
# 给创建的线程设置名称
当出现线上故障时,如果线程没有设置名称很多时候很难定位到是哪个线程出现问题。
Thread thread = new Thread("thread-http");
1
# 如何停止线程
不要使用thread的stop和destory方法来中断线程,可能会出现不可预料的结果。正确的做法是使用标记状态字段来控制。
示例代码中running必须使用volatile来修饰
/**
* 停止线程示例并发编程
*
* @author fengjianxin
*/
public class ThreadStop extends Thread {
private volatile boolean running = true;
public static void main(String[] args) {
ThreadStop thread = new ThreadStop();
thread.start();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
Thread.currentThread().interrupt();
}
thread.setRunning(false);
// 不要使用stop停止线程
// thread.stop();
}
@Override
public void run() {
while (running) {
}
System.out.println("stop...");
}
public boolean isIsRunning() {
return running;
}
public void setRunning(boolean running) {
this.running = running;
}
}
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
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
# 要响应线程中断异常
当线程抛出InterruptedException时,表示当前线程有阻塞操作,并且该线程任务被意外终止,同时终止原因难以预测,完善的程序应该对这种情况进行处理。
教程:https://www.ibm.com/developerworks/cn/java/j-jtp05236.html (opens new window)
# ThreadLocal使用
ThreadLocal通常定义成静态变量,用于共享当前线程数据,位置线程上下文数据,隐式传参。在线程结束时必须调用remove方法,否则可能会导致内存泄漏。
例如:spring aop事务管理,将数据库connection放到ThreadLocal,来保证打开和关闭事务的connection是同一个,而无需显示调用和将connection显式传递。
# 谨慎使用Executors创建线程池
不要直接使用Executors创建线程池,因为Executors默认创建线程池的队列大小为Integer.MAX_VALUE,大量并发可能会导致内存泄漏。正确的做法是使用ThreadPoolExecutor来创建。
以下摘自阿里巴巴java开发手册
Executors各个方法的弊端:
- newFixedThreadPool和newSingleThreadExecutor: 主要问题是堆积的请求处理队列可能会耗费非常大的内存,甚至OOM。
- newCachedThreadPool和newScheduledThreadPool: 主要问题是线程数最大数是Integer.MAX_VALUE,可能会创建数量非常多的线程,甚至OOM。
Positive example 1:
//org.apache.commons.lang3.concurrent.BasicThreadFactory
ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1,
new BasicThreadFactory.Builder().namingPattern("example-schedule-pool-%d").daemon(true).build());
1
2
3
2
3
Positive example 2:
ThreadFactory namedThreadFactory = new ThreadFactoryBuilder()
.setNameFormat("demo-pool-%d").build();
//Common Thread Pool
ExecutorService pool = new ThreadPoolExecutor(5, 200,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(1024), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy());
pool.execute(()-> System.out.println(Thread.currentThread().getName()));
pool.shutdown();//gracefully shutdown
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
Positive example 3:
<bean id="userThreadPool"
class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="corePoolSize" value="10" />
<property name="maxPoolSize" value="100" />
<property name="queueCapacity" value="2000" />
<property name="threadFactory" value= threadFactory />
<property name="rejectedExecutionHandler">
<ref local="rejectedExecutionHandler" />
</property>
</bean>
//in code
userThreadPool.execute(thread);
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
Last Updated: 2024/04/23, 01:30:37