多线程知识总结

  1. 如何优雅的关闭线程与线程池?

关闭线程:

当 JVM 中不存在任何一个正在运行的非守护线程时,则 JVM 进程即会退出。对于在主线程中开辟的一个线程,setDaemon(true)将该线程设置为守护线程。当主线程退出时,JVM 会随之退出运行,守护线程同时也会被回收,即使里面是个死循环也不碍事。

守护线程拥有自动结束自己生命周期的特性,而非守护线程不具备这个特点。守护线程确保在程序退出时,或者说 JVM 退出时,线程能够自动关闭。

关闭线程池:

e339275fbde249a0be4492900d9d0722.png

线程池状态变换图

  • RUNNING:能接受新提交的任务,并且也能处理阻塞队列中的任务;
  • SHUTDOWN:关闭状态,不再接受新提交的任务,但却可以继续处理阻塞队列中已保存的任务。
  • STOP:不能接受新任务,也不处理队列中的任务,会中断正在处理任务的线程。在线程池处于 RUNNING 或 SHUTDOWN 状态时,调用shutdownNow() 方法会使线程池进入到该状态;
  • TIDYING:如果所有的任务都已终止了,workerCount (有效线程数) 为0,线程池进入该状态后会调用 terminated() 方法进入TERMINATED 状态。
  • TERMINATED:在terminated()方法执行完后进入该状态。

一般情形下关闭线程池:

// 线程池进入SHUTDOWN状态,停止接受新的任务

executorService.shutdown();

// 等待线程池任务完成

executorService.awaitTermination(30, TimeUnit.SECONDS);

在Spring中,如果线程池作为其他Bean中的属性,则需要在Bean的destroy时,关闭线程池

@PreDestroy

public void destroy() {

    executorService.shutdown();

    executorService.awaitTermination(30, TimeUnit.SECONDS);

}

  1. 使用线程池时如何注意队列过大造成的阻塞或OOM问题?

如下例所示,自定义线程池可以设置工作队列长度

executorService = new ThreadPoolExecutor(threadNum, threadNum, 0L, TimeUnit.MILLISECONDS,
        new ArrayBlockingQueue<>(QUEUE_SIZE),
        new BasicThreadFactory.Builder().namingPattern("process-%d").daemon(true).build());

在实际开发中,多线程里设置多线程,只需在最外层设置即可。

  1. 线程或线程池定义的位置如何选择?

Manager类中定义线程池作为其他Bean中的属性, 避免反复创建销毁消耗性能。

  1. Java多线程中向线程传递参数有哪几种方法?

(1)通过构造函数传递参数

public class MyThread1 extends Thread

{

    private String name;

    public MyThread1(String name)

    {

        this.name = name;

    }

    public void run()

    {

        System.out.println("hello " + name);

    }

    public static void main(String[] args)

    {

        Thread thread = new MyThread1("world");

        thread.start();        

    }

}

(2)通过构造函数传递参数

public class MyThread2 implements Runnable

{

    private String name;

    public void setName(String name)

    {

        this.name = name;

    }

    public void run()

    {

        System.out.println("hello " + name);

    }

    public static void main(String[] args)

    {

        MyThread2 myThread = new MyThread2();

        myThread.setName("world");

        Thread thread = new Thread(myThread);

        thread.start();

    }

}

(3)通过回调函数传递数据

class Data

{

    public int value = 0;

}

class Work

{

    public void process(Data data, Integer numbers)

    {

        for (int n : numbers)

        {

            data.value += n;

        }

    }

}

public class MyThread3 extends Thread

{

    private Work work;

 

    public MyThread3(Work work)

    {

        this.work = work;

    }

    public void run()

    {

        java.util.Random random = new java.util.Random();

        Data data = new Data();

        int n1 = random.nextInt(1000);

        int n2 = random.nextInt(2000);

        int n3 = random.nextInt(3000);

        work.process(data, n1, n2, n3);   // 使用回调函数

        System.out.println(String.valueOf(n1) + "+" + String.valueOf(n2) + "+"

                + String.valueOf(n3) + "=" + data.value);

    }

    public static void main(String[] args)

    {

        Thread thread = new MyThread3(new Work());

        thread.start();

    }

}

  1. 其他坑:
  •            (1)任务提交后长时间没有执行

任务进入了队列,线程还在执行之前的任务。本质原因是对线程和队列的优先级认识不深刻,有一种错觉以为是所有线程都忙的时候才进入任务队列。实际上相反,是队列满的时候才会新建线程(线程数大于core size时)。

  •       (2)线程池中线程执行任务中无故消失(从日志可以看出,任务并未完成,也没有抛出异常)

一般情况下,代码中只会去捕捉RuntimeException,如果抛出Error则会导致线程退出,而异常信息又没有拿到。最佳的解决办法是给线程池设置UncaughtExceptionHandler

  1. 以构造函数的方式传入注解:

public class RunnableTask implements Runnable {

    private int projectId;

    private TransactionService transactionService; // 这个就是注解注入

    RunnableTask() {

    }

    // 注解在别的Controller中

    // @Autowired

    // private TransactionService transactionService;

    // 以构造参数的方式传递给Runnable即可

    public RunnableTask(int projectId, TransactionService transactionService) {

        this.projectId = projectId;

        this.transactionService = transactionService;

    }

    @Override

    public void run() {

            ...

    }

7、如果try中没有异常,则顺序为try→finally,如果try中有异常,则顺序为try→catch→finally。但是当try、catch、finally中加入return之后

(1)finally中的代码总会被执行。

(2)当try、catch中有return时,也会执行finally。return的时候,要注意返回值的类型,是否受到finally中代码的影响。

(3)finally中有return时,会直接在finally中退出,导致try、catch中的return失效。

详解地址:https://www.cnblogs.com/pcheng/p/10968841.html

8、尽量不要在方法中return 线程,会报错,还会降低效率。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值