JAVA多线程提高六:java5线程并发库的应用_线程池

前面我们对并发有了一定的认识,并且知道如何创建线程,创建线程主要依靠的是Thread 的类来完成的,那么有什么缺陷呢?如何解决?

一、对比new Thread
new Thread的弊端
a. 每次new Thread新建对象性能差。
b. 线程缺乏统一管理,可能无限制新建线程,相互之间竞争,及可能占用过多系统资源导致死机或oom。
c. 缺乏更多功能,如定时执行、定期执行、线程中断。
相比new Thread,Java提供的四种线程池的好处在于:
a. 重用存在的线程,减少对象创建、消亡的开销,性能佳。
b. 可有效控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞争,避免堵塞。
c. 提供定时执行、定期执行、单线程、并发数控制等功能。

二、创建线程池方法

一般通过调用Executors的工厂方法创建线程池,常用的有以下5种类:

//创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待
Executors.newFixedThreadPool
//创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行
Executors.newSingleThreadExecutor
//创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程
Executors.newCachedThreadPool
//创建一个定长线程池,支持定时及周期性任务执行
Executors.newScheduledThreadPool
//创建一个单线程化的线程池,支持定时及周期性任务执行
Executors.newSingleThreadScheduledExecutor

上面每种出基本的参数使用外,还可以根据个人需要加入ThreadFactory(java的线程生成工厂,可以自己重写做些命名日志之类)参数。如:newFixedThreadPool有重载两种方法:newFixedThreadPool(int) 和 newFixedThreadPool(int,ThreadFactory)

调用上面的方法其实都是创建ThreadPoolExecutor对象,只是传入的参数不同而已。 
ThreadPoolExecutor的类方法:ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, ...),可定义线程池固定的线程数及最大线程数。

三、执行

一般通过调用execute(Runnable) 或者 submit(Callable)执行线程

四、关闭

详细可参考: 
深入理解JAVA–线程池(二):shutdown、shutdownNow、awaitTermination 
JAVA线程池shutdown和shutdownNow的区别 
threadPoolExecutor 中的 shutdown() 、 shutdownNow() 、 awaitTermination() 的用法和区别

threadPool.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.

List<Runnable> 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.

awaitTermination(long timeout, TimeUnit unit):等所有已提交的任务(包括正在跑的和队列中等待的)执行完或者超时或者被中断。

线程池状态: 
isShutdown():if this executor has been shut down. 
isTerminated():if all tasks have completed following shut down.isTerminated is never true unless either shutdown or shutdownNow was called first

如何选择: 
* 优雅的关闭,用shutdown() 
* 想立马关闭,并得到未执行任务列表,用shutdownNow() 
* 优雅的关闭,并允许关闭声明后新任务能提交,用awaitTermination()

五、常用线程池

newFixedThreadPool

要应用场景:固定线程数的线程池比较常见,如处理网络请求等。常用!!!

使用示例

/ 调用execute
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
for (int i = 0; i < 10; i++) {
    final int index = i;
    fixedThreadPool.execute(new Runnable() {
        public void run() {
        System.out.println(index);
    });
}  

// 调用submit
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
List<Future> futureList = new ArrayList<Future>();
for (int i = 0; i < 10; i++) {
    final int index = i;
    futureList.add(fixedThreadPool.submit(new Callable<Integer>() {
        public Integer call() throws Exception {
            return index;
        }
    }));
}
for(Future future : futureList) {
    try {
        future.get();
    } catch (Exception e) {
        future.cancel(true);
    }
}

newCachedThreadPool

主要应用场景:需要很极致的速度,因为newCachedThreadPool不会等待空闲线程。但有一定风险,如果一个任务很慢或者阻塞,并且请求很多,就容易造成线程泛滥,会导致整个系统的假死(无法接收处理新的请求),所以实际上个人不建议使用这个方法。

使用示例:execute、submit类似于newFixedThreadPool

ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
    final int index = i;
    cachedThreadPool.execute(new Runnable() {
        public void run() {
            System.out.println(index);
        }
    });
}

newSingleThreadExecutor

使用示例:execute、submit类似于newFixedThreadPool

ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
for (int i = 0; i < 10; i++) {
  final int index = i;
  singleThreadExecutor.execute(new Runnable() {
    public void run() {
    System.out.println(index);
  });
}  

newScheduledThreadPool

执行newScheduledThreadPool返回类ScheduledExecutorService(其实新建类ScheduledThreadPoolExecutor)。 
通过类ScheduledThreadPoolExecutor的定义:class ScheduledThreadPoolExecutor extends ThreadPoolExecutor implements ScheduledExecutorService及源码可知: 
1、ScheduledThreadPoolExecutor是ScheduledExecutorService的实现类。 
2、ScheduledThreadPoolExecutor继承了类ThreadPoolExecutor

通常我们通过Executors工厂方法(Executors.newScheduledThreadPool)获取类ScheduledExecutorService或直接通过new ScheduledThreadPoolExecutor类创建定时任务。

ScheduledThreadPoolExecutor有以下重载方法: 
方法返回接口:ScheduledFuture。接口定义为:public interface ScheduledFuture<V> extends Delayed, Future<V>。对应着有以下几种常用的方法: 
cancel:取消任务 
getDelay:获取任务还有多久执行



public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) 
延迟delay执行,只执行一次

使用示例

// 延迟3s执行
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
scheduledThreadPool.schedule(new Runnable() {
  public void run() {
    System.out.println("delay 3 seconds");
  }
}, 3, TimeUnit.SECONDS); 

//延迟1秒后每3秒执行一次
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
ScheduledFuture<?> scheduledFuture = scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
  public void run() {
    System.out.println("delay 1 seconds, and excute every 3 seconds");
  }
}, 1, 3, TimeUnit.SECONDS);  

//获取下一次任务还有多久执行
scheduledFuture.getDelay(TimeUnit.SECONDS)

public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit)
延迟initialDelay开始执行执行,之后周期period执行,类比Timer的scheduleAtFixedRate方法,固定频率执行。当某个任务执行的时间超过period时间,则可能导致下一个定时任务延迟,但是不会出现并发执行的情况。当任何一个任务执行跑出异常,后面的任务将不会执行。所以你如果想保住任务都一直被周期执行,那么catch一切可能的异常。通过取消任务(调用cancel方法)或者终止executor(调用shutdown方法)可使任务停止。



public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) 
延迟initialDelay开始执行执行,之后周期period执行,类比Timer的schedule方法,固定延迟执行。当上一个任务执行后,等待delay时间才执行下一个,因此也不会并发执行的情况。当任何一个任务执行跑出异常,后面的任务将不会执行。所以你如果想保住任务都一直被周期执行,那么catch一切可能的异常。通过取消任务(调用cancel方法)或者终止executor(调用shutdown方法)可使任务停止。

六、ScheduledThreadPoolExecutor与Timer的区别

直接参考:Timer与ScheduledThreadPoolExecutor

参考:

java常用线程池 
Java 四种线程池的用法分析 
JAVA线程池shutdown和shutdownNow的区别

原文地址:https://www.cnblogs.com/pony1223/p/9286519.html

时间: 2024-10-07 06:00:26

JAVA多线程提高六:java5线程并发库的应用_线程池的相关文章

9.Java5线程并发库的应用

1 import java.util.concurrent.ExecutorService; 2 import java.util.concurrent.Executors; 3 import java.util.concurrent.TimeUnit; 4 5 /** 6 * java5线程并发库的应用 7 * 线程池工具类 Executors 8 * 9 * @author LiTaiQing 10 * 11 */ 12 public class ThreadPoolTest { 13 14

Java多线程与并发库高级应用-java5线程并发库

java5 中的线程并发库 主要在java.util.concurrent包中 还有 java.util.concurrent.atomic子包和java.util.concurrent.lock子包

Android多线程研究(7)——Java5中的线程并发库

从这一篇开始我们将看看Java 5之后给我们添加的新的对线程操作的API,首先看看api文档: java.util.concurrent包含许多线程安全.测试良好.高性能的并发构建块,我们先看看atomic包下的AtomicInteger. import java.util.concurrent.atomic.AtomicInteger; public class AtomicIntegerTest { private static AtomicInteger data = new Atomic

Java多线程与并发库高级应用之线程数据交换Exchanger

JDK1.5提供了Exchanger用于两个线程的数据交换.两个线程先后到达交换点,先到达的线程会等待后到达的线程,然后两个线程互相交换数据,交换后双方持对方的数据. Exchanger只提供了一个构造器: Exchanger():创建一个新的Exchanger. Exchanger中也只有两个方法: V exchange(V x): 等待另一个线程到达此交换点(除非当前线程被中断),然后将给定的对象传送给该线程,并接收该线程的对象. V exchange(V x, long timeout,

【java并发】线程并发库的使用

1. 线程池的概念 在java5之后,就有了线程池的功能了,在介绍线程池之前,先来简单看一下线程池的概念.假设我开了家咨询公司,那么每天会有很多人过来咨询问题,如果我一个个接待的话,必然有很多人要排队,这样效率就很差,我想解决这个问题,现在我雇几个客服,来了一个咨询的,我就分配一个客服去接待他,再来一个,我再分配个客服去接待--如果第一个客服接待完了,我就让她接待下一个咨询者,这样我雇的这些客服可以循环利用.这些客服就好比不同的线程,那么装这些线程的容器就称为线程池. 2. Executors的

线程高级应用-心得5-java5线程并发库中Lock和Condition实现线程同步通讯

1.Lock相关知识介绍 好比我同时种了几块地的麦子,然后就等待收割.收割时,则是哪块先熟了,先收割哪块. 下面举一个面试题的例子来引出Lock缓存读写锁的案例,一个load()和get()方法返回值为空时的情况:load()的返回值是一个代理对象,而get()却是一个实实在在的对象:所以当返回对象为空是,get()返回null,load()返回一个异常对象:具体分析如下: 一个读写锁的缓存库案例:用上面那道面试题分析则很好理解: 线程阻塞问题:运用多个Condition对象解决 2. Lock

线程高级应用-心得4-java5线程并发库介绍,及新技术案例分析

1.  java5线程并发库新知识介绍 2.线程并发库案例分析 1 package com.itcast.family; 2 3 import java.util.concurrent.ExecutorService; 4 import java.util.concurrent.Executors; 5 import java.util.concurrent.TimeUnit; 6 7 public class ThreadPoolTest { 8 9 /** 10 * @param args

线程高级应用-心得8-java5线程并发库中同步集合Collections工具类的应用及案例分析

1.  HashSet与HashMap的联系与区别? 区别:前者是单列后者是双列,就是hashmap有键有值,hashset只有键: 联系:HashSet的底层就是HashMap,可以参考HashSet的类源码,默认构造方法为: public HashSet(){ map = new HashMap<key,Object> } 就是HashSet只用HashMap的键,而不用他的值,前者的值可以程序员随便指定,反正不用 2.  线程并发库中的集合优路劣之分 HashMap和HashSet如果在

Java 多线程(六) synchronized关键字详解

Java 多线程(六) synchronized关键字详解 多线程的同步机制对资源进行加锁,使得在同一个时间,只有一个线程可以进行操作,同步用以解决多个线程同时访问时可能出现的问题. 同步机制可以使用synchronized关键字实现. 当synchronized关键字修饰一个方法的时候,该方法叫做同步方法. 当synchronized方法执行完或发生异常时,会自动释放锁. 下面通过一个例子来对synchronized关键字的用法进行解析. 1.是否使用synchronized关键字的不同 例子