线程池就是创建若干个可执行线程放入一个池(容器)中,有任务需要执行时,就从线程池中获取一个线程用来执行,使用完毕放回线程池中。
JVM在HotSpot的线程模型下,Java线程会一对一映射为内核线程,也就说Java中每创建/回收一个线程都会去内核创建/回收,涉及到内核操作的都是很消耗资源的,这就可能导致创建/回收线程所消耗的资源比处理任务所消耗的资源更多,为了提高资源的利用率,就引入了线程池的概念。
这样提高了资源的利用率,提高了线程的可复用性
源码
public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()));//容量为Integer.MAX_VALUE }
使用
ExecutorService threadPool = Executors.newSingleThreadExecutor();//创建只有一个线程的线程池 for (int i = 0; i < 10; i++) { threadPool.execute(()->{ System.out.println(Thread.currentThread().getName()+" ok"); }); } threadPool.shutdown();//线程池使用完毕必须要手动关闭
结果
pool-1-thread-1 ok pool-1-thread-1 ok pool-1-thread-1 ok pool-1-thread-1 ok pool-1-thread-1 ok
源码
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor( nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());//容量为Integer.MAX_VALUE }
使用
ExecutorService threadPool = Executors.newFixedThreadPool(2);//创建固定数量的线程池 for (int i = 0; i < 10; i++) { threadPool.execute(()->{ System.out.println(Thread.currentThread().getName()+" ok"); }); } threadPool.shutdown();
结果
pool-1-thread-2 ok pool-1-thread-1 ok pool-1-thread-2 ok pool-1-thread-1 ok pool-1-thread-2 ok pool-1-thread-1 ok pool-1-thread-2 ok pool-1-thread-2 ok pool-1-thread-2 ok pool-1-thread-1 ok
源码
public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor( 0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); }
使用
ExecutorService threadPool = Executors.newCachedThreadPool();//创建可伸缩的线程池 for (int i = 0; i < 100; i++) { threadPool.execute(()->{ System.out.println(Thread.currentThread().getName()+" ok"); }); } threadPool.shutdown();
结果
pool-1-thread-2 ok pool-1-thread-6 ok pool-1-thread-5 ok pool-1-thread-1 ok pool-1-thread-4 ok pool-1-thread-3 ok pool-1-thread-9 ok pool-1-thread-8 ok pool-1-thread-7 ok pool-1-thread-10 ok
1、有新的任务来临时,当前线程数量不足corePoolSize时,会由executor指定的TheradFactory创建一个新的线程来执行任务
2、有新的任务来临时,当前线程数量达到corePoolSize时,workQueue未满时,会将任务加入workQueue中,等待执行
3、有新的任务来临时,当前线程数量到达了corePoolSize且workQueue队列已满,则会判断当前线程数量是否小于maximumPoolSize,如果满足就由executor指定的TheradFactory新建一个线程来执行任务
4、如果大于maximumPoolSize由拒绝策略处理
5、如果当先线程数量大于corePoolSize,只要有线程空闲的时间超过keepAliveTime指定的时间,就会将这个线程回收
CPU密集型:以计算为主的程序。以计算为主的程序线程数最好和CPU核心数相同(N),可以减少CPU切换带来的消耗,以获得最大执行效率。
IO密集型:以input/output为主的程序。由于IO的速度远不及CPU的速度,CPU在处理IO时往往伴随着等待,为获得最大的执行效率一般将程序的线程数设置为IO任务的2倍(2N)
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0)); private static final int COUNT_BITS = Integer.SIZE - 3; //高3位用来表示线程状态 private static final int CAPACITY = (1 << COUNT_BITS) - 1;//低29位用来表示线程数量// =000 11111... // runState is stored in the high-order bits private static final int RUNNING = -1 << COUNT_BITS; // 111 00000... private static final int SHUTDOWN = 0 << COUNT_BITS; // 000 00000... private static final int STOP = 1 << COUNT_BITS; // 001 00000... private static final int TIDYING = 2 << COUNT_BITS; // 010 00000... private static final int TERMINATED = 3 << COUNT_BITS; // 011 00000... // 线程池的状态 private static int runStateOf(int c) { return c & ~CAPACITY; } // 线程池中工作线程的数量 private static int workerCountOf(int c) { return c & CAPACITY; } // 计算ctl的值,等于运行状态“加上”线程数量 private static int ctlOf(int rs, int wc) { return rs | wc; }
作者巧妙的使用Integer的前三位表示线程的状态,后29位来表示工作线程数量。也就是说线程数量最多只能有2^29-1