铁匠 铁匠
首页
收藏
golang
java
架构之路
常用算法
  • Java
  • nginx
  • 系统运维
  • 系统安全
  • mysql
  • redis
参考文档
关于
链接
  • 分类
  • 标签
  • 归档

专注、不予评判地关注当下
首页
收藏
golang
java
架构之路
常用算法
  • Java
  • nginx
  • 系统运维
  • 系统安全
  • mysql
  • redis
参考文档
关于
链接
  • 分类
  • 标签
  • 归档
  • java api 文档
  • 版本特性

  • jvm

  • 网络编程

  • 并发编程

  • java
  • 并发编程
FengJianxin
2019-03-10
目录

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

# 要响应线程中断异常

当线程抛出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各个方法的弊端:

  1. newFixedThreadPool和newSingleThreadExecutor: 主要问题是堆积的请求处理队列可能会耗费非常大的内存,甚至OOM。
  2. 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

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

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
#并发编程
最近更新
01
go-kit学习指南 - 多协议支持
04-19
02
go-kit学习指南 - 中间件
04-19
03
go-kit开发微服务 - 服务注册与发现
04-19
更多文章>
Theme by Vdoing | Copyright © 2016-2024 铁匠 | 粤ICP备15021633号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式