一、java 线程的创建方式

  • 1.继承Thread类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    public class Demo extends Thread {
    public static void main(String[] args) {
    new Demo().start();
    }

    @Override
    public void run() {
    while (true) {
    try {
    Thread.sleep(100);
    System.out.println(11);
    } catch (Exception e) {

    }
    }
    }
    }
  • 2.实现runnable接口

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    public class Demo implements Runnable {

    public static void main(String[] args) {
    new Thread(new Demo()).start();
    }

    @Override
    public void run() {
    while (true) {
    try {
    Thread.sleep(100);
    System.out.println(11);
    } catch (Exception e) {
    }
    }
    }
    }
  • 3.使用lambda表达式(比较推荐这种方式)

    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
    public class Demo {

    public static void main(String[] args) {
    new Thread(new Runnable() {
    @Override
    public void run() {
    while (true) {
    try {
    Thread.sleep(100);
    System.out.println(11);
    } catch (Exception e) {
    }
    }
    }
    }).start();
    }
    }

    public class Demo {

    public static void main(String[] args) {
    new Thread(() -> {
    while (true) {
    try {
    Thread.sleep(100);
    System.out.println(11);
    } catch (Exception e) {
    }
    }
    }).start();
    }
    }
  • 4.实现callable接口(可以拿到任务的结果)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    public class Demo implements Callable<Integer> {

    public static void main(String[] args) {
    try {
    // 创建FutureTask任务 优点可以拿到执行的结果
    FutureTask<Integer> futureTask = new FutureTask<>(new Demo());
    // 将FutureTask传给线程
    Thread thread = new Thread(futureTask);
    thread.start();
    System.out.println(futureTask.get());
    } catch (Exception e) {
    e.printStackTrace();
    }
    }

    @Override
    public Integer call() throws Exception {
    return 1;
    }
    }
  • 5.使用线程池创建线程

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    public class Demo implements Runnable {

    public static void main(String[] args) {
    ExecutorService executorService = Executors.newFixedThreadPool(10);
    executorService.execute(new Demo());
    }

    @Override
    public void run() {
    try {
    while (true) {
    try {
    Thread.sleep(100);
    System.out.println(11);
    } catch (Exception e) {
    }
    }
    } catch (Exception e) {
    e.printStackTrace();
    }
    }
    }
    • 为什么不建议使用Executors来创建线程池
      Executors的newFixedThreadPool构造方法如下:

      1
      2
      3
      4
      5
       public static ExecutorService newFixedThreadPool(int nThreads) {
      return new ThreadPoolExecutor(nThreads, nThreads,
      0L, TimeUnit.MILLISECONDS,
      new LinkedBlockingQueue<Runnable>());
      }

      发现创建的队列为LinkedBlockingQueue,是一个无界阻塞队列,如果使用该线程池执行任务如果任务过多就会不断的添加到队列中,任务越多占用的内存就越多,最终可能耗尽内存,导致OOM。—OOM内存被使用完
      对于 Executors的newSingleThreadExecutor构造方法如下:

      1
      2
      3
      4
      5
      6
      7
      public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
      return new FinalizableDelegatedExecutorService
      (new ThreadPoolExecutor(1, 1,
      0L, TimeUnit.MILLISECONDS,
      new LinkedBlockingQueue<Runnable>(),
      threadFactory));
      }

      同样也是LinkedBlockingQueue队列,会造成OOM内存消耗殆尽的事故

    • 总结
      除开有可能造成OOM之外,我们使用Executors来创建线程池也不能自定义现成的名字,不利于排查问题,所以建议直接使用ThreadPoolExecutor来定义线程池,可以灵活的来控制线程。

二、线程池有那些状态

  • RUNNING

    Accept new tasks and process queued tasks
    表示线程池正常运行,既能够接受新的任务,也会正常处理队列中的任务。

  • SHUTDOWN

    Don’t accept new tasks,but process queued tasks
    当调用线程池的shutdown()方法时,线程池就会进入SHUTDOWN状态,表示线程池处于正在关闭状态,此状态下线程池不会接受新的任务,但是会继续把队列中的任务处理完毕。

  • STOP

    Don’t accept new tasks, don’t process queued tasks, and interrupt in-progress tasks
    当调用线程池的shutdownnow()方法时,线程池就进入STOP状态,表示线程池处于正在停止状态,此状态下线程池既不会接受新任务了,也不会处理队列中的任务,并且正在运行的线程也会被中断

  • TIDYING

    All tasks have terminated, workerCount is zero, the thread transitioning to state TIDYINGwill run the terminated0 hook method
    线程池中没有线程在运行后,线程池的状态就会自动变为TIDYING,并且会调用terminated0,该方法是空方法,留给程序员进行扩展。

  • TERMINATED

    terminated() has completed
    terminated()方法执行完之后,线程池状态就会变为TERMINATED