1、ExecutorService的介绍

ExecutorService 接口继承了Executor 接口,是Executor 的子接口。
Executors类 提供工厂方法用来创建不同类型的线程池。Executors是工具类,他提供对ThreadPoolExecutor的封装,会产生几种线程池供大家使用。
关于 Executor 、ExecutorService、Executors三者的区别:
参考:Executor, ExecutorService 和 Executors 间的区别与联系 - 夏威夷8080 - 博客园
UML简要类图关系:

2、ExecutorService 的获取 - submit()方法
注:返回值都是 ExecutorService
3种方法以及每种方法对应的一个重载的方法。
如重载方法:newCachedThreadPool(ThreadFactory threadFactory):
ThreadFactory 也是一个接口,该接口允许我们自己去写实现类,在实现类的内部只需要创建一个线程对象即可——这样的话,相当于我们自己(程序员)可以控制线程池中每一个线程对象的创建。

上面的 “无界队列方式” —— 是指任务累加或者说缓存的时候,是不限制数量的。
(1)newCachedThreadPool() 方法、
以及其重载的方法法 newCachedThreadPool(ThreadFactory threadFactory)
:创建一个默认的线程池对象,里面的线程可重用,且在第一次使用时才创建;
重载的:线程池中的所有线程都使用ThreadFactory来创建,这样的线程无需手动启动,自动执行。
代码示例:MyTest01
package com.zhoulz.demo02;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
/**
 * 练习 Executors 获取ExecutorService,然后调用方法,提交任务;
 * newCachedThreadPool()方法、
 *         以及其重载的方法newCachedThreadPool(ThreadFactory threadFactory)
 */
public class MyTest01 {
    public static void main(String[] args) {
        //test1(); // 下面test1()中的内容被提取出来了—— 快捷键Shift+Alt+M:提取方法Extract Method
                   // 提取的原因是因为方便测试。接下来要测试newCachedThreadPool()重载的方法
        test2();
    }
    //(1)练习newCachedThreadPool()方法
    private static void test1() {
        // 1、使用工厂类——获取线程池对象
        final ExecutorService es = Executors.newCachedThreadPool();
        // 然后就可以调用方法 :如提交任务、shutdown()方法关闭提交
        // 2、提交任务 —— 任务可以是Runnable类型的对象,也可以是Callable类型的对象
        // 为了代码的整洁性,下面单独写了一个任务类。(也可以写一个匿名内部类)
        // 可以通过循环的方式来提交任务
        for (int i = 1; i <= 10; i++) {
            es.submit(new MyRunnable(i));
        }
    }
    //(2)练习newCachedThreadPool()重载的方法—— (在里面直接传参数 ThreadFactory threadFactory)
    private static void test2() {
        // 1、使用工厂类——获取线程池对象
        final ExecutorService es = Executors.newCachedThreadPool(new ThreadFactory() {
            int n = 1;
             // 匿名内部类的内部,允许我们直接创建一个线程对象。所以下面return的时候,可以直接new
            @Override
            public Thread newThread(Runnable r) {
                //return null;
                // 直接 new,并把Runnable的对象作为一个实参
                return new Thread(r,"自定义的线程名称" + n++);
                // 这样,创建出来的线程 new Thread()就可以和这个任务Runnable r 绑定在一起了!!!
                // 然后就可以执行了。。。
                // 还可以指定线程名称、加编号 n ...见上
            }
        });
        // 2、提交任务(这里是通过匿名内部类的方式,见上面)
        for (int i = 1; i <= 10; i++) {
            es.submit(new MyRunnable(i));
        }
    }
}
/**
 * 任务类:包含一个任务编号,在任务中,打印出是哪一个线程正在执行任务
 */
class MyRunnable implements Runnable{
    // 为了对任务做一个区分,可以加一个编号,不能通过run()方法传进来,所以要通过构造方法
    private int id;
    public MyRunnable(int id) {
        this.id = id;
    }
    @Override
    public void run() {
        // 获取线程的名称,打印一句话(这就是要执行的任务)
        String name = Thread.currentThread().getName();
        System.out.println(name + "执行了任务。。。" + id);
    }
}结果:
test01:创建了10个线程

test02:—— 可见10个线程都是自定义创建的。
 
  
(2)newFixedThreadPool(int nThreads) 方法、以及其重载的方法 newFixedThreadPool(int nThreads, ThreadFactory threadFactory)
: 创建一个可重用固定线程数的线程池 ;
重载的:创建一个可重用固定线程数的线程池且线程池中的所有线程都使用ThreadFactory来创建。
代码示例:MyTest02(基本同MyTest01)
package com.zhoulz.demo02;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
/**
 * 练习 Executors 获取ExecutorService,然后调用方法,提交任务;
 *(2)newFixedThreadPool(int nThreads)方法、以及其重载的方法
 *         newFixedThreadPool(int nThreads, ThreadFactory threadFactory)
 */
public class MyTest02 {
    public static void main(String[] args) {
        //test1();
        test2();
    }
    //(1)练习newFixedThreadPool(int nThreads)方法
    private static void test1() {
        // 1、使用工厂类——获取线程池对象
        final ExecutorService es = Executors.newFixedThreadPool(3);
        // 2、提交任务
        for (int i = 1; i <= 10; i++) {
            es.submit(new MyRunnable2(i));
        }
    }
    //(2)练习newCachedThreadPool()重载的方法
    private static void test2() {
        // 1、使用工厂类——获取线程池对象
        final ExecutorService es = Executors.newFixedThreadPool(3,new ThreadFactory() {
            int n = 1;
            @Override
            public Thread newThread(Runnable r) {
                return new Thread(r,"自定义的线程名称" + n++ +"-zlz");
            }
        });
        // 2、提交任务
        for (int i = 1; i <= 10; i++) {
            es.submit(new MyRunnable2(i));
        }
    }
}
/**
 * 任务类:包含一个任务编号,在任务中,打印出是哪一个线程正在执行任务
 */
class MyRunnable2 implements Runnable{
    private int id;
    public MyRunnable2(int id) {
        this.id = id;
    }
    @Override
    public void run() {
        // 获取线程的名称,打印一句话
        String name = Thread.currentThread().getName();
        System.out.println(name + "执行了任务。。。" + id);
    }
}结果:
test01:只创建了3个线程

test02:自定义的创建了3个线程
这是匿名内部类中自定义的线程对象(任务?)加了“-zlz”作区分

结合如下输出结果,可见 执行的任务/线程是匿名内部类里的,而不是MyRunnable2里的。

但是为什么没执行呢?(下面还是提交了任务 new MyRunnable2(i) 的啊)

(3)newSingleThreadExecutor()方法、
以及其重载的方法 newSingleThreadExecutor(ThreadFactory threadFactory)
:创建一个使用单个 worker 线程的 Executor,以无界队列方式来运行该线程;
重载的:创建一个使用单个 worker 线程的 Executor,且线程池中的所有线程都使用ThreadFactory来创建。
代码示例:MyTest03(基本同MyTest01、MyTest02)
package com.zhoulz.demo02;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
/**
 * 练习 Executors 获取ExecutorService,然后调用方法,提交任务;
 *(3)newSingleThreadExecutor()方法、以及其重载的方法
 *        newSingleThreadExecutor(ThreadFactory threadFactory)
 */
public class MyTest03 {
    public static void main(String[] args) {
        //test1();
        test2();
    }
    //(1)练习newFixedThreadPool(int nThreads)方法
    private static void test1() {
        // 1、使用工厂类——获取线程池对象
        final ExecutorService es = Executors.newSingleThreadExecutor();
        // 2、提交任务
        for (int i = 1; i <= 10; i++) {
            es.submit(new MyRunnable3(i));
        }
    }
    //(2)练习newCachedThreadPool()重载的方法
    private static void test2() {
        // 1、使用工厂类——获取线程池对象
        final ExecutorService es = Executors.newSingleThreadExecutor(new ThreadFactory() {
            int n = 1;
            @Override
            public Thread newThread(Runnable r) {
                return new Thread(r,"自定义的线程名称" + n++ +"-zlz");
            }
        });
        // 2、提交任务
        for (int i = 1; i <= 10; i++) {
            es.submit(new MyRunnable3(i));
        }
    }
}
/**
 * 任务类:包含一个任务编号,在任务中,打印出是哪一个线程正在执行任务
 */
class MyRunnable3 implements Runnable{
    private int id;
    public MyRunnable3(int id) {
        this.id = id;
    }
    @Override
    public void run() {
        // 获取线程的名称,打印一句话
        String name = Thread.currentThread().getName();
        System.out.println(name + "执行了任务。。。" + id);
    }
}结果:
test01:只创建了1个线程

test02:自定义的只创建了1个线程




![[附源码]JAVA毕业设计文物管理系统(系统+LW)](https://img-blog.csdnimg.cn/586efd9fb30c45968fb0538fff4e1f5f.png)















