• Java多线程的4种实现方式


    Java有四种实现多线程的方式:

    1).继承Thread类

    2).实现Runnable接口

    3).实现Callable接口

    4).使用线程池

    前三种实现方式的代码:

     1 public class MultiThread {
     2   //继承Thread类
     3     static class MyThread1 extends Thread{
     4         @Override
     5         public void run() {
     6             System.out.println(Thread.currentThread().getName()+": extends Thread方式");
     7         }
     8     }
     9   //实现Runnable接口
    10     static class MyThread2 implements Runnable{
    11         @Override
    12         public void run() {
    13             System.out.println(Thread.currentThread().getName()+": implements Runnable方式");
    14         }
    15     }
    16   //实现Callable接口
    17     static class MyThread3 implements Callable<String>{
    18         @Override
    19         public String call() throws Exception {
    20             return Thread.currentThread().getName()+": implements Callable<V>方式";
    21         }
    22     }
    23 
    24     public static void main(String[] args) throws Exception{
    25         Thread thread1 = new MyThread1();
    26         Thread thread2 = new Thread(new MyThread2());
    27         FutureTask<String> futureTask = new FutureTask<>(new MyThread3());
    28         Thread thread3 = new Thread(futureTask);
    29 
    30         thread1.start();
    31         thread2.start();
    32         thread3.start();
    33         System.out.println(futureTask.get());
    34     }
    35 }
    运行结果:
    Thread-0: extends Thread方式 Thread-1: implements Runnable方式 Thread-2: implements Callable<V>方式 

    line26,27行当传入一个Runnable target参数给Thread后,Thread的run()方法就会调用target.run(),参考Thread类部分源代码:

    public class Thread implements Runnable {
        public Thread(Runnable target) {
    init(null, target, "Thread-" + nextThreadNum(), 0);
    }
      @Override
      public void run() {
       if (target != null) {
      target.run();
      }
      }
    }

    1.继承Thread本质上也是实现Runnable接口。

    2.实现Callable接口的任务线程能返回执行结果,而实现Runnable接口的线程不能返回结果

    3.使用Callable的方式时候需要用FutureTask<>进行包装(适配),FutureTask实现了Runnable和Future,通过future里面的get()方法来得到返回值。需要注意的是get()方法是阻塞的,就是说取不到值会使主线程一直等待。

    4.生产中几乎都会使用线程池。

    线程池:用来控制运行的线程的数量,处理过程中将任务放入等待队列,然后在线程创建后启动这些任务。如果线程数量超过了最大数量(maximumPoolSize),超出数量的线程将会在等待队列排队等候。如果等待队列已满,再进来的任务就会按照拒绝策略拒绝。

    线程池的特点:线程复用,控制最大并发数,管理线程。

    线程池的优势:

    1.降低资源消耗,通过复用线程来降低创建和销毁线程的消耗。

    2.提高响应速度,当任务到达时不需要等待创建线程。

    3.提高线程的可管理性,使用线程池可以进行统一的分配,监控和调优。

    java自带的线程池的实现:

         //固定数量线程的线程池
            ExecutorService threadPool1 = Executors.newFixedThreadPool(cpuNum);
            //一个线程的线程池
            ExecutorService threadPool2 = Executors.newSingleThreadExecutor();
            //多个线程的线程池
            ExecutorService threadPool3 = Executors.newCachedThreadPool();
            //Java8新特性
         ExecutorService threadPool3 = Executors.newWorkStealingPool();

    上面几线程池的底层都是ThreadPoolExecutor(),ThreadPoolExecutor是线程池的核心类。ThreadPoolExecutor的构造器最多有7个可配参数:

    ThreadPoolExecutor的7个参数:

    • corePoolSize:核心池的大小,这个参数跟后面讲述的线程池的实现原理有非常大的关系。在创建了线程池后,默认情况下,线程池中并没有任何线程,而是等待有任务到来才创建线程去执行任务,除非调用了prestartAllCoreThreads()或者prestartCoreThread()方法,从这2个方法的名字就可以看出,是预创建线程的意思,即在没有任务到来之前就创建corePoolSize个线程或者一个线程。默认情况下,在创建了线程池后,线程池中的线程数为0,当有任务来之后,就会创建一个线程去执行任务,当线程池中的线程数目达到corePoolSize后,就会把到达的任务放到缓存队列当中;
    • maximumPoolSize:线程池最大线程数,这个参数也是一个非常重要的参数,它表示在线程池中最多能创建多少个线程;
    • keepAliveTime:表示线程没有任务执行时最多保持多久时间会终止。默认情况下,只有当线程池中的线程数大于corePoolSize时,keepAliveTime才会起作用,直到线程池中的线程数不大于corePoolSize,即当线程池中的线程数大于corePoolSize时,如果一个线程空闲的时间达到keepAliveTime,则会终止,直到线程池中的线程数不超过corePoolSize。但是如果调用了allowCoreThreadTimeOut(boolean)方法,在线程池中的线程数不大于corePoolSize时,keepAliveTime参数也会起作用,直到线程池中的线程数为0;
    • unit:参数keepAliveTime的时间单位,有7种取值:
      TimeUnit.DAYS;//天
      TimeUnit.HOURS;//小时
      TimeUnit.MINUTES;//分钟
      TimeUnit.SECONDS;//秒
      TimeUnit.MILLISECONDS;//毫秒
      TimeUnit.MICROSECONDS;//微妙
      TimeUnit.NANOSECONDS;//纳秒
    • workQueue:一个阻塞队列,用来存储等待执行的任务,这个参数的选择也很重要,会对线程池的运行过程产生重大影响,一般来说,这里的阻塞队列有以下几种选择:ArrayBlockingQueue和PriorityBlockingQueue使用较少,一般使用LinkedBlockingQueue和Synchronous。线程池的排队策略与BlockingQueue有关。
    • threadFactory:线程工厂,主要用来创建线程;
    • handler:表示当拒绝处理任务时的策略,有以下四种取值:
      ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。 
      ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。 
      ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
      ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务 

    线程池详细原理可以参考:https://www.cnblogs.com/dolphin0520/p/3932921.html

  • 相关阅读:
    java.lang.UnsupportedClassVersionError: action/Login : Unsupported major.minor version 52.0 (unable to load class action.Login)异常
    main方法和args参数
    建立maven工程pom.xml报错:web.xml is missing and <failOnMissingWebXml> is set to true
    遍历js中数组或者对象
    setAttribute设置无效
    javascript中用setAttribute给元素添加colspan属性无效
    ssm回顾笔记(一)
    struts2学习笔记(一)
    esay-ui学习笔记(一)
    农银电商项目学习笔记(一)
  • 原文地址:https://www.cnblogs.com/dream2true/p/10817009.html
Copyright © 2020-2023  润新知