栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

JAVA多线程技术-线程池创建方式和原理

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

JAVA多线程技术-线程池创建方式和原理

1.通过Executors创建

Java里面线程池的顶级接口是Executor,但是严格意义上讲Executor并不是一个线程池,而只是一个执行线程的工具。真正的线程池接口是ExecutorService。

下面这张图完整描述了线程池的类体系结构。

**Executor:**一个接口,其定义了一个接收Runnable对象的方法executor,其方法签名为executor(Runnable command),

**ExecutorService:**是一个比Executor使用更广泛的子类接口,其提供了生命周期管理的方法,以及可跟踪一个或多个异步任务执行状况返回Future的方法

**AbstractExecutorService:**ExecutorService执行方法的默认实现

ScheduledExecutorService:一个可定时调度任务的接口

ScheduledThreadPoolExecutor:ScheduledExecutorService的实现,一个可定时调度任务的线程池

**ThreadPoolExecutor:**线程池,可以通过调用Executors以下静态工厂方法来创建线程池并返回一个ExecutorService对象

(1)创建缓存线程池

Executors.newCacheThreadPool():可缓存线程池,先查看线程池中有没有之前创建的线程,如果有则直接使用。否则就新创建一个新的线程加入线程池中,我们经常用此类线程池来执行一些业务处理时间很短的任务。

源码

    public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue());
    }

    
    public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue(),
                                      threadFactory);
    }

通过源码可以看出是对ThreadPoolExecutor封装。阻塞队列不装线程,最大线程数是Integer最大值,可以不断创建线程。

注意线程太多会发生OOM。

代码实现

//缓存线程池
        ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
        for (int i=0;i<10;i++) {
            //模拟线程调用的时间间隔
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            cachedThreadPool.submit(()->{
                //模拟业务处理时间
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("newCachedThreadPool创建线程池" + " " + Thread.currentThread().getName());
            });
        }

结果

newCachedThreadPool创建线程池 pool-1-thread-1
newCachedThreadPool创建线程池 pool-1-thread-1
newCachedThreadPool创建线程池 pool-1-thread-1
newCachedThreadPool创建线程池 pool-1-thread-1
newCachedThreadPool创建线程池 pool-1-thread-1
newCachedThreadPool创建线程池 pool-1-thread-1
newCachedThreadPool创建线程池 pool-1-thread-1
newCachedThreadPool创建线程池 pool-1-thread-1
newCachedThreadPool创建线程池 pool-1-thread-1
newCachedThreadPool创建线程池 pool-1-thread-1

调大业务处理时间Thread.sleep(1000);,由于新创建的线程没有空闲,所以会一直创建新的线程,执行结果如下:

newCachedThreadPool创建线程池 pool-1-thread-1
newCachedThreadPool创建线程池 pool-1-thread-2
newCachedThreadPool创建线程池 pool-1-thread-3
newCachedThreadPool创建线程池 pool-1-thread-4
newCachedThreadPool创建线程池 pool-1-thread-5
newCachedThreadPool创建线程池 pool-1-thread-6
newCachedThreadPool创建线程池 pool-1-thread-7
newCachedThreadPool创建线程池 pool-1-thread-8
newCachedThreadPool创建线程池 pool-1-thread-9
newCachedThreadPool创建线程池 pool-1-thread-10
(2)创建固定长度线程池

Executors.newFixedThreadPool():创建一个固定(指定)长度可重用的线程池,可以控制最大创建数,超过最大长度之后就会放入到队列进行等待。最大线程数=核心线程数。

源码

public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue());
    }

源码可以看出只是留了一个传线程数的口子,最大线程数=核心线程数。

代码实现

//固定线程池
ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(2);
for (int i=0;i<10;i++) {
  //模拟线程调用的时间间隔
  try {
    Thread.sleep(100);
  } catch (InterruptedException e) {
    e.printStackTrace();
  }

  newFixedThreadPool.submit(()->{
    //模拟业务处理时间
    try {
      Thread.sleep(3000);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    System.out.println("newFixedThreadPool创建线程池" + " " + Thread.currentThread().getName());
  });
}

结果

newFixedThreadPool创建线程池 pool-1-thread-1
newFixedThreadPool创建线程池 pool-1-thread-2
newFixedThreadPool创建线程池 pool-1-thread-1
newFixedThreadPool创建线程池 pool-1-thread-2
newFixedThreadPool创建线程池 pool-1-thread-1
newFixedThreadPool创建线程池 pool-1-thread-2
newFixedThreadPool创建线程池 pool-1-thread-1
newFixedThreadPool创建线程池 pool-1-thread-2
newFixedThreadPool创建线程池 pool-1-thread-1
newFixedThreadPool创建线程池 pool-1-thread-2

创建了两个线程的固定线程池,线程会进入等待队列,等有空闲线程再执行。使用LinkedBlockingQueue大小为Integer.MAX_VALUE。注意队列里放太多任务也会发生OOM的。

(3)定时执行的线程池

Executors.newScheduledThreadPool():创建一个支持定时或周期性的执行任务线程池,可以延时执行,可以用做执行定时任务的线程池。

源码

  public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue());
    }

定时线程池是根据延时队列来实现的。

代码实现

//可定时执行的线程池
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yy-MM-dd hh:mm:ss");
ScheduledExecutorService newScheduledThreadPool = Executors.newScheduledThreadPool(2);
//参数依次为:执行线程、初始化延时、线程调用时间间隔、计时单位
newScheduledThreadPool.scheduleAtFixedRate(new Runnable() {
  @Override
  public void run() {
    System.out.println("newScheduledThreadPool创建线程池" + " " + Thread.currentThread().getName() + "执行时间" + simpleDateFormat.format(new Date()));
  }
},5,10, TimeUnit.SECONDS);

结果

newScheduledThreadPool创建线程池 pool-1-thread-1执行时间22-07-19 11:02:04
newScheduledThreadPool创建线程池 pool-1-thread-1执行时间22-07-19 11:02:14
newScheduledThreadPool创建线程池 pool-1-thread-1执行时间22-07-19 11:02:24
newScheduledThreadPool创建线程池 pool-1-thread-1执行时间22-07-19 11:02:34
newScheduledThreadPool创建线程池 pool-1-thread-1执行时间22-07-19 11:02:44
newScheduledThreadPool创建线程池 pool-1-thread-1执行时间22-07-19 11:02:54
newScheduledThreadPool创建线程池 pool-1-thread-1执行时间22-07-19 11:03:04

第一个线程延时5s,线程间执行间隔10s。

scheduleAtFixedRate和scheduleWithFixedDelay区别

假设线程耗时1s,定时执行3s,则scheduleWithFixedDelay其实是4s,

scheduleAtFixedRate:固定周期运行。

scheduleWithFixedDelay:任务结束时间周期进行。

(4)单线程化线程池

Executors.newSingleThreadExecutor():创建一个单线程化线程池,它只能用一个工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

源码

public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue()));
    }

最大线程数=核心线程数=1

代码实现

//单线程池
ExecutorService newSingleThreadExecutor = Executors.newSingleThreadExecutor();
for (int i=0;i<10;i++) {
//模拟线程调用的时间间隔
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}

newSingleThreadExecutor.submit(()->{
//模拟业务处理时间
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("newSingleThreadExecutor创建线程池" + " " + Thread.currentThread().getName());
});
}

结果

newSingleThreadExecutor创建线程池 pool-1-thread-1
newSingleThreadExecutor创建线程池 pool-1-thread-1
newSingleThreadExecutor创建线程池 pool-1-thread-1
newSingleThreadExecutor创建线程池 pool-1-thread-1
newSingleThreadExecutor创建线程池 pool-1-thread-1
newSingleThreadExecutor创建线程池 pool-1-thread-1
newSingleThreadExecutor创建线程池 pool-1-thread-1
newSingleThreadExecutor创建线程池 pool-1-thread-1
newSingleThreadExecutor创建线程池 pool-1-thread-1
newSingleThreadExecutor创建线程池 pool-1-thread-1

执行代码会看到同一时间只有一个线程执行,其余的任务都会有序等待且有序的执行。

2.自己创建

执行代码

//ThreadFactory参数,可以通过实现自己手动写一个实现ThreadFactory的类作为参数放到这里
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 1, 60L,
                TimeUnit.SECONDS, new LinkedBlockingDeque<>(1000), new ThreadFactory() {
            @Override
            public Thread newThread(Runnable r) {   
                return new Thread(r,"自定义线程池"+r.hashCode());
            }
        });

        for (int i=0;i<10;i++) {
            //模拟线程调用的时间间隔
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            threadPoolExecutor.submit(()->{
                //模拟业务处理时间
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("newCachedThreadPool创建线程池" + " " + Thread.currentThread().getName());
            });
        }
    }

结果

newCachedThreadPool创建线程池 自定义线程池445884362
newCachedThreadPool创建线程池 自定义线程池445884362
newCachedThreadPool创建线程池 自定义线程池445884362
newCachedThreadPool创建线程池 自定义线程池445884362
newCachedThreadPool创建线程池 自定义线程池445884362
newCachedThreadPool创建线程池 自定义线程池445884362
newCachedThreadPool创建线程池 自定义线程池445884362
newCachedThreadPool创建线程池 自定义线程池445884362
newCachedThreadPool创建线程池 自定义线程池445884362
newCachedThreadPool创建线程池 自定义线程池445884362

注意:以上线程池用完记得关闭。通过调用线程池的 shutdown 或 shutdownNow 方法来关闭线程池。

Executor和Executors区别

**Executor:**一个接口,其定义了一个接收Runnable对象的方法executor,其方法签名为executor(Runnable command)。

Executors:是对线程池的包装,前面讲到了前三种线程池的创建。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1020174.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号