并发工具包与线程连接池

        并发是伴随着多核处理器的诞生而“席卷大地”的,为了充分利用硬件资源,诞生了多线程技术。但是多线程又存在资源竞争的问题,引发了同步和互斥的问题,JDK1.5推出的java.util.concurrent(简称JUC)并发工具包,就是专门来解决这些问题的。

 

new Thread的弊端:

        ◎new Thread新建对象,性能差。

        ◎线程缺乏统一的管理,可能无限制的新建线程,相互竞争,严重时会占用过多系统资源或OOM(内存溢出)。

 

ThreadPool线程池:

        重用存在的线程,减少对象新建、消亡的开销。

        ◎线程总数可控,提高资源的利用率。

        ◎避免过多资源竞争,避免阻塞。

        ◎提供额外功能,定时执行、定期执行,监控等。

扫描二维码关注公众号,回复: 3753819 查看本文章

 

JUC提供了调度器对象Executors来创建线程池,可创建的线程池有四种

①CachedThreadPool可缓存线程池

特点: 1.如果线程池中无空闲线程,则创建;有,则利用起来。

          2.线程总数固定。

          3.可以进行自动线程回收。

②FixedThreadPool定长线程池

特点: 1.如果线程池中有空闲线程,则利用起来;如果线程池中的所有线程都在执行任务,那么后续任务进入等待状态;
             直到有空闲的线程了,该线程再执行后续任务。

         2.无线程数上限。

注:如果有多个后续任务的话,那么空闲下来的线程会根据FIFO原则,来选择要执行哪一个线程。
      (FIFO:即First Input First Output,先入先出;还有LIFI:即Last In First Out后入先出)

③SingleThreadExecutor单线程线程池

说明: 用来模拟单线程的线程池

④ScheduledThreadPool调度线程池

说明: 一般用于处理定时任务;与其类似的还有Timer;在实际做项目时,我们既不用ScheduledThreadPool,
         也不用Timer;而是用成熟的定时任务框架Quartz或Spring自带的定时调度。

注:Quartz或Spring定时调度的具体用法,可详见我的这篇博客
     https://blog.csdn.net/justry_deng/article/details/80666508

 

 

四种线程池的创建使用示例

CachedThreadPool可缓存线程池,使用示例:

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

/**
 * CachedThreadPool的创建
 *
 * @author JustryDeng
 * @date 2018/10/11 18:47
 */
public class ExecutorsCreateCachedThreadPool {
    private static Integer count = 10000;
    private static Object object = new Object();
    public static void main(String[] args) throws InterruptedException {

        // -> 创建可缓存线程池
        ExecutorService executorService = Executors.newCachedThreadPool();

        for (int i = 1; i <= 10000; i++) {
            // 使用lambda表达式简单实现Runnable接口的run方法
            executorService.execute(() -> {
                // 只有获得了object的锁的线程,才能操作
                synchronized (object) {
                    count--;
                }
            });
        }
        // 当线程池中所有线程都运行完毕后,关闭线程池
        executorService.shutdown();
        // 主线程阻塞2秒再输出count的值,为了避免输出打印count的值时,其余线程还没计算完;导致输出的不是count的最终值
        Thread.sleep(2000);
        System.out.println(count);
    }
}

FixedThreadPool定长线程池,使用示例:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * FixedThreadPool的创建
 *
 * @author JustryDeng
 * @date 2018/10/11 18:47
 */
public class ExecutorsCreateFixedThreadPool {
    private static Integer count = 10000;
    private static Lock lock = new ReentrantLock();
    public static void main(String[] args) throws InterruptedException {

        // -> 创建定长线程池(该线程池中总共存在200个线程)
        ExecutorService executorService = Executors.newFixedThreadPool(200);

        for (int i = 1; i <= 10000; i++) {
            // 使用lambda表达式简单实现Runnable接口的run方法
            executorService.execute(() -> {
                // 使用重入锁,保证线程安全同步
                lock.lock();
                try {
                    count--;
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }

            });
        }
        // 当线程池中所有线程(包括排着队的)都运行完毕后,关闭线程池
        executorService.shutdown();
        // 主线程阻塞2秒再输出count的值,为了避免输出打印count的值时,其余线程还没计算完;导致输出的不是count的最终值
        Thread.sleep(2000);
        System.out.println(count);
    }
}

SingleThreadExecutor单线程线程池,使用示例:

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

/**
 * SingleThreadExecutor的创建
 *
 * @author JustryDeng
 * @date 2018/10/11 18:47
 */
public class ExecutorsCreateSingleThreadExecutor {
    private static Integer count = 10000;
    public static void main(String[] args) throws InterruptedException {

        // -> 创建定单线程线程池
        ExecutorService executorService = Executors.newSingleThreadExecutor();

        for (int i = 1; i <= 10000; i++) {
            // 使用lambda表达式简单实现Runnable接口的run方法
            // 因为是单线程池,所以不需要任何其他操作,就能保证数据的安全准确性
            executorService.execute(() -> count--);
        }
        // 当线程池中所有线程(包括排着队的)都运行完毕后,关闭线程池
        executorService.shutdown();
        // 主线程阻塞2秒再输出count的值,为了避免输出打印count的值时,其余线程还没计算完;导致输出的不是count的最终值
        Thread.sleep(2000);
        System.out.println(count);
    }
}

ScheduledThreadPool调度线程池,使用示例:

import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * ScheduledThreadPool的创建
 *
 * @author JustryDeng
 * @date 2018/10/11 18:47
 */
public class ExecutorsCreateScheduledThreadPool {
    public static void main(String[] args) {

        // -> 创建定时调度线程池(初始化核心线程数为5)
        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5);

        // 使用lambda表达式简单实现Runnable接口的run方法
        System.out.println("当前时间是:" + new Date());
        scheduledExecutorService.schedule(() -> System.out.println("10秒后输出此语句! -> " + new Date()),10, TimeUnit.SECONDS);
        // 当线程池中所有线程(包括排着队的)都运行完毕后,关闭线程池
        scheduledExecutorService.shutdown();
    }
}

 

声明:本文是学习笔记,主要学习自以下视频
微笑学习视频
           《Java多线程与并发实战视频课程》,齐毅 

微笑如有不当之处,欢迎指正
微笑本文已经被收录进《程序员成长笔记(三)》,笔者JustryDeng

猜你喜欢

转载自blog.csdn.net/justry_deng/article/details/83018025