关于线程池执行与终止方法的使用

———— 通常线程池的执行方法有两种execute和submit,那么他们有什么区别呢?

1.接受任务的类型

execute 只能接受Runnable类型的任务

 void execute(Runnable command);
复制代码

submit不管是Runnable还是Callable类型的任务都可以接受,但是Runnable返回值均为void,所以使用Future的get()获得的还是null

 <T> Future<T> submit(Callable<T> task);
 <T> Future<T> submit(Runnable task, T result);
 Future<?> submit(Runnable task);
复制代码

2.execute方法适用于那些不需要关注返回值的场景,我们只需要把要执行的任务丢进线程池

 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 public class Thread02 {  
 public static void main(String[] args) throws Exception {
    ExecutorService pool = Executors.newFixedThreadPool(1);
    pool.execute(() -> {
        System.out.println("我爱学习,我爱java");
    });
  }
 } 
复制代码

运行结果

我爱学习,我爱java
复制代码

submit方法适用于需要关注返回值的场景,通常这种的我们在工作中用的比较多,可以通过Future的get()方法得到线程的运行结果

     import java.util.concurrent.Callable;
     import java.util.concurrent.ExecutorService;
     import java.util.concurrent.Executors;
     import java.util.concurrent.Future;
     public class Thread02 {
     public static void main(String[] args) throws Exception {
      ExecutorService pool = Executors.newFixedThreadPool(1);
     //我们取一个String类型的返回值
      Future<String> future = pool.submit(new Callable<String>() {
        public String call() throws Exception {
            return "我爱java";
        }
      });
      String result = future.get();
      System.out.println("线程的运行结果为: " + result);
      
      //我们取一个boolean类型的返回值
      Future<Boolean> future2 = pool.submit(new Callable<Boolean>() {
        public Boolean call() throws Exception {
            return 6 > 7;
        }
       });
      System.out.println("线程的运行结果为:" + future2.get());
      //取一个Runnable类型的任务
       Future future3 = pool.submit(()->{
        System.out.println();
     });
      }
     }
复制代码

其运行结果为

 线程的运行结果为: 我爱java
 线程的运行结果为:false
 线程的运行结果为:null
复制代码

———— 线程池执行后先让其停止有什么方法呢?通常线程池的停止方法有两种:shutdown()和shutdownNow(),那么他们又有什么区别呢?

1.shutdown

  /**
 * Initiates an orderly shutdown in which previously submitted
 * tasks are executed, but no new tasks will be accepted.
 * Invocation has no additional effect if already shut down.
 *
 * <p>This method does not wait for previously submitted tasks to
 * complete execution.  Use {@link #awaitTermination awaitTermination}
 * to do that.
 *
 * @throws SecurityException if a security manager exists and
 *         shutting down this ExecutorService may manipulate
 *         threads that the caller is not permitted to modify
 *         because it does not hold {@link
 *         java.lang.RuntimePermission}{@code ("modifyThread")},
 *         or the security manager's {@code checkAccess} method
 *         denies access.
 */
void shutdown();
复制代码

观看其源码的说明可以知道,shutdown()这种方法是有序的进行停止,在此之前提交的任务都可以继续执行,而执行此方法后如果继续往线程池丢任务,则不会再去执行任务。

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Test01 {
public static void main(String[] args) throws Exception {
    ExecutorService pool = Executors.newFixedThreadPool(1);
    for (int i = 0; i < 6; i++) {
        System.err.println(i);
        pool.execute(() -> {
            try {
                Thread.sleep(1000);
                System.out.println("我爱java,我爱学习");
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
    }
    Thread.sleep(2000);
    //停止线程池
    pool.shutdown();
    pool.execute(()->{
        System.out.println("我不想上班");
    });
  }
 }
复制代码

运行结果

 0
 1
 2
 3
 4
 5
 我爱java,我爱学习
 我爱java,我爱学习
 Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task com.test.Test01$$Lambda$2/2129789493@27d6c5e0 rejected from java.util.concurrent.ThreadPoolExecutor@4f3f5b24[Shutting down, pool size = 1, active threads = 1, queued tasks = 3, completed tasks = 2]
at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2047)
at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:823)
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1369)
at com.test.Test01.main(Test01.java:22)
 我爱java,我爱学习
 我爱java,我爱学习
 我爱java,我爱学习
 我爱java,我爱学习
复制代码

通过测试我们先创建一个大小为1的线程池,往里面丢6个任务,然后调用shutdown()方法去停止线程池,最后我们再去执行一个任务 可以发现我们刚开始放进去的任务都有序的执行了,当我们执行为shutdown()方法后,再去调用线程池,此时线程池已经不工作了。

2.shutdownNow()

 /**
 * Attempts to stop all actively executing tasks, halts the
 * processing of waiting tasks, and returns a list of the tasks
 * that were awaiting execution.
 *
 * <p>This method does not wait for actively executing tasks to
 * terminate.  Use {@link #awaitTermination awaitTermination} to
 * do that.
 *
 * <p>There are no guarantees beyond best-effort attempts to stop
 * processing actively executing tasks.  For example, typical
 * implementations will cancel via {@link Thread#interrupt}, so any
 * task that fails to respond to interrupts may never terminate.
 *
 * @return list of tasks that never commenced execution
 * @throws SecurityException if a security manager exists and
 *         shutting down this ExecutorService may manipulate
 *         threads that the caller is not permitted to modify
 *         because it does not hold {@link
 *         java.lang.RuntimePermission}{@code ("modifyThread")},
 *         or the security manager's {@code checkAccess} method
 *         denies access.
 */
List<Runnable> shutdownNow();
复制代码

观看其源码的说明可以知道,shutdownNow()这种方法是停止所有线程(正在执行的和等待的),并返回任务列表(等待执行的任务),已经执行的任务是不会返回的,我们可以通过代码去验证

 import java.util.List;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;

 public class Test01 {
 public static void main(String[] args) throws Exception {
    ExecutorService pool = Executors.newFixedThreadPool(1);
    for (int i = 0; i < 6; i++) {
        System.err.println(i);
        pool.execute(() -> {
            try {
                //1秒执行一个
                Thread.sleep(1000);
                System.out.println("我爱java,我爱学习");
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
    }
    //休眠两秒
  Thread.sleep(2000);
  List<Runnable> runnables= pool.shutdownNow();
  System.out.println("未执行的线程"+runnables);
  System.out.println("未执行的线程的数量"+runnables.size());
  }
}
复制代码

运行结果

 0
 1
 2
 3 
 4
 5
 我爱java,我爱学习
 我爱java,我爱学习
 未执行的线程[com.test.Test01$$Lambda$1/931919113@7ef20235, com.test.Test01$$Lambda$1/931919113@7ef20235,    com.test.Test01$$Lambda$1/931919113@7ef20235, com.test.Test01$$Lambda$1/931919113@7ef20235]
 未执行的线程的数量4
复制代码

通过上面代码演示,我们先放6个任务进如线程池,每秒执行一个,然后休眠2秒,通过运行结果我们可以知道在休眠的2秒钟执行了两个线程,所以还有四个线程未执行,输出结果为4;

当我们把休眠时间变为2500毫秒(2.5秒)其输出结果为:

  0
  1
  2
  3
  4
  5
 我爱java,我爱学习
 我爱java,我爱学习
 未执行的线程[com.test.Test01$$Lambda$1/931919113@7ef20235, com.test.Test01$$Lambda$1/931919113@7ef20235, com.test.Test01$$Lambda$1/931919113@7ef20235]
 未执行的线程的数量3
 java.lang.InterruptedException: sleep interrupted
 at java.lang.Thread.sleep(Native Method)
 at com.test.Test01.lambda$main$0(Test01.java:14)
 at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
 at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
 at java.lang.Thread.run(Thread.java:745)
复制代码

可以看到当我们让其休眠2.5秒后。在这段时间执行完成了2个线程,第三个线程正在执行中(还未执行完),而shutdownNow()方法是停止所有线程(执行中的和等待执行的),返回正在等待执行的线程。所以其返回正在等待执行的数量为3

猜你喜欢

转载自juejin.im/post/5d26d6a2e51d45599e019e4a