Java线程池使⽤和常⽤参数
多线程问题:
1、java中为什么要使⽤多线程
使⽤多线程,可以把⼀些⼤任务分解成多个⼩任务来执⾏,多个⼩任务之间互不影像,同时进⾏,这样,充分利⽤了cpu资源。
2、java中简单的实现多线程的⽅式
继承Thread类,重写run⽅法;
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28class MyTread extends Thread{
public void run() {
  System.out.println(Thread.currentThread().getName());
}
}
实现Runable接⼝,实现run⽅法;
class MyRunnable implements Runnable{
  public void run() {
    System.out.println(Thread.currentThread().getName());  }
}
class ThreadTest {
  public static void main(String[] args) {
    MyTread thread = new Mythread();
    thread.start(); //开启⼀个线程
    MyRunnable myRunnable = new MyRunnable();
    Thread runnable = new Thread(myRunnable);
    runnable.start();  //开启⼀个线程
  }
}
3、java线程的状态
创建:当new了⼀个线程,并没有调⽤start之前,线程处于创建状态;
就绪:当调⽤了start之后,线程处于就绪状态,这是,线程调度程序还没有设置执⾏当前线程;
运⾏:线程调度程序执⾏到线程时,当前线程从就绪状态转成运⾏状态,开始执⾏run⽅法⾥边的代码;
阻塞:线程在运⾏的时候,被暂停执⾏(通常等待某项资源就绪后在执⾏,sleep、wait可以导致线程阻塞),这是该线程处于阻塞状态;死亡:当⼀个线程执⾏完run⽅法⾥边的代码或调⽤了stop⽅法后,
该线程结束运⾏
4、为什么要引⼊线程池
当我们需要的并发执⾏线程数量很多时,且每个线程执⾏很短的时间就结束了,这样,我们频繁的创建、销毁线程就⼤⼤降低了⼯作效率(创建和销毁线程需要时间、资源)。
java中的线程池可以达到这样的效果:⼀个线程执⾏完任务之后,继续去执⾏下⼀个任务,不被销毁,这样线程利⽤率提⾼了。
5、java中的线程池(ThreadPoolExecutor)
说起java中的线程池,就想到urrent.ThreadPoolExecutor。ThreadPoolExecutor类是java线程池中的核⼼类。他的实现⽅式有四种:
1
2
3
4public class ThreadPoolExecutor extends AbstractExecutorService {
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51  public ThreadPoolExecutor(int corePoolSize,
    int maximumPoolSize,
    long keepAliveTime,
    TimeUnit unit,
    BlockingQueue<Runnable> workQueue) {
    this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,    Executors.defaultThreadFactory(), defaultHandler);
  }
   public ThreadPoolExecutor(int corePoolSize,
    int maximumPoolSize,
    long keepAliveTime,
    TimeUnit unit,
    BlockingQueue<Runnable> workQueue,
    ThreadFactory threadFactory) {
    this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,    threadFactory, defaultHandler);
  }
  public ThreadPoolExecutor(int corePoolSize,
    int maximumPoolSize,
    long keepAliveTime,
    TimeUnit unit,
    BlockingQueue<Runnable> workQueue,
    RejectedExecutionHandler handler) {
    this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,    Executors.defaultThreadFactory(), handler);
  }
  public ThreadPoolExecutor(int corePoolSize,
    int maximumPoolSize,
    long keepAliveTime,
    TimeUnit unit,
    BlockingQueue<Runnable> workQueue,
    ThreadFactory threadFactory,
    RejectedExecutionHandler handler) {
    if(corePoolSize < 0||
      maximumPoolSize <= 0||
      maximumPoolSize < corePoolSize ||
      keepAliveTime < 0)
      throw new IllegalArgumentException();
    if(workQueue == null|| threadFactory == null|| handler == null)
      throw new NullPointerException();
    PoolSize = corePoolSize;
    this.maximumPoolSize = maximumPoolSize;
    this.workQueue = workQueue;
    this.keepAliveTime = Nanos(keepAliveTime);
    this.threadFactory = threadFactory;
    this.handler = handler;
}
通过ThreadPoolExecutor类的源码可以看出,ThreadPoolExecutor类继承AbstractExecutorService,提供四个构造⽅法,通过构造⽅法可以看出前⾯三个最终掉了最后⼀个
下⾯介绍下构造⽅法中的参数:
corePoolSize:线程池的⼤⼩。线程池创建之后不会⽴即去创建线程,⽽是等待线程的到来。当当前执⾏的线程数⼤于改值是,线程会加⼊到缓冲队列;
maximumPoolSize:线程池中创建的最⼤线程数;
keepAliveTime:空闲的线程多久时间后被销毁。默认情况下,改值在线程数⼤于corePoolSize时,对超出corePoolSize值得这些线程起作⽤。
unit:TimeUnit枚举类型的值,代表keepAliveTime时间单位,可以取下列值:
TimeUnit.DAYS; //天
  TimeUnit.HOURS; //⼩时
  TimeUnit.MINUTES; //分钟
  TimeUnit.SECONDS; //秒
  TimeUnit.MILLISECONDS; //毫秒
  TimeUnit.MICROSECONDS; //微妙
  TimeUnit.NANOSECONDS; //纳秒
workQueue:阻塞队列,⽤来存储等待执⾏的任务,决定了线程池的排队策略,有以下取值:
  ArrayBlockingQueue;
  LinkedBlockingQueue;
  SynchronousQueue;
  threadFactory:线程⼯⼚,是⽤来创建线程的。默认new Executors.DefaultThreadFactory();
handler:线程拒绝策略。当创建的线程超出maximumPoolSize,且缓冲队列已满时,新任务会拒绝,有以下取值:  ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
  ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。
  ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前⾯的任务,然后重新尝试执⾏任务(重复此过程)  ThreadPoolExecutor.CallerRunsPolicy:由调⽤线程处理该任务
以下是具体的实现⽅式:
1
2
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38//默认策略。使⽤该策略时,如果线程池队列满了丢掉这个任务并且抛出RejectedExecutionException异常class AbortPolicy implements RejectedExecutionHandler{
  public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
    throw new RejectedExecutionException("Task "+ r.toString() +
    " rejected from "+
    String());
  }
}
//如果线程池队列满了,会直接丢掉这个任务并且不会有任何异常
class DiscardPolicy implements RejectedExecutionHandler{
  public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
  }
}
//丢弃最⽼的,会将最早进⼊队列的任务删掉腾出空间,再尝试加⼊队列
class DiscardOldestPolicy implements RejectedExecutionHandler{
  public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
    if(!executor.isShutdown()) {
      //移除队头元素
      Queue().poll();
    //再尝试⼊队
      ute(r);
    }
  }
}
//主线程会⾃⼰去执⾏该任务,不会等待线程池中的线程去执⾏
class CallerRunsPolicy implements RejectedExecutionHandler{
  public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
    if(!executor.isShutdown()) {
      //直接执⾏run⽅法
      r.run();
    }
  }
}
以下是ThreadPoolExecutor具体的继承结构
1 2 3public abstract class AbstractExecutorService implements ExecutorService { }
这是⼀个抽象类,实现了ExecutorService接⼝,并实现了ExecutorService⾥边的⽅法,下⾯看下ExecutorService接⼝的具体实现
1 2 3 4 5public interface ExecutorService extends Executor {  void shutdown();
  List<Runnable> shutdownNow();
  boolean isShutdown();
  boolean isTerminated();
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20  boolean awaitTermination(long timeout, TimeUnit unit)
  throws InterruptedException;
  <T> Future<T> submit(Callable<T> task);
  <T> Future<T> submit(Runnable task, T result);
  Future<?> submit(Runnable task);
  <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException;  <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
  long timeout, TimeUnit unit)
  throws InterruptedException;
java线程池创建的四种  <T> T invokeAny(Collection<? extends Callable<T>> tasks)
  throws InterruptedException, ExecutionException;
  <T> T invokeAny(Collection<? extends Callable<T>> tasks,
  long timeout, TimeUnit unit)
  throws InterruptedException, ExecutionException, TimeoutException;
}
ExecutorService继承Executor接⼝,下⾯是Executor接⼝的具体实现
1 2 3public interface Executor {
  void execute(Runnable command); }
Executor接⼝是顶层接⼝,只声明了⼀个execute⽅法,该⽅法是⽤来执⾏传递进来的任务的。回过头来,咱么重新看ThreadPoolExecutor类,改类⾥边有以下两个重要的⽅法:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24public void execute(Runnable command) {
  if(command == null)
    throw new NullPointerException();
  int c = ();
  if(workerCountOf(c) < corePoolSize) {
    if(addWorker(command, true))
      return;
    c = ();
  }
  if(isRunning(c) && workQueue.offer(command)) {    int recheck = ();
    if(! isRunning(recheck) && remove(command))      reject(command);
    else if(workerCountOf(recheck) == 0)
    addWorker(null, false);
  }else if(!addWorker(command, false))
    reject(command);
}
public<T> Future<T> submit(Callable<T> task) {
  if(task == null) throw new NullPointerException();  RunnableFuture<T> ftask = newTaskFor(task);
  execute(ftask);
  return ftask;
}
execute()⽅法是Executor中声明的⽅法,在ThreadPoolExecutor有了具体的实现,这个⽅法是ThreadPoolExecutor的核⼼⽅法,
通过这个⽅法可以向线程池提交⼀个任务,交由线程池去执⾏
submit()⽅法是ExecutorService中声明的⽅法,在AbstractExecutorService中进⾏了实现,Executor中并没有对其进⾏重写。从实现中可以看出,submit⽅法最终也调⽤了execute
⽅法,也是执⾏⼀个⼈去,但submit⽅法可以返回执⾏结果,利⽤Future来获取任务执⾏结果。
6、Spring中的线程池
Spring中的线程池是由ThreadPoolTaskExecutor类来实现的。该类的实现原理最终也是调⽤了java中的ThreadPoolExecutor类中的⼀些⽅法。具体的实现读者可以⾃⼰去翻阅Spring
的源码,这⾥笔者就不罗列了。我们看下ThreadPoolTaskExecutor的初始化。
ThreadPoolTaskExecutor有两种常⽤的有两种初始化⽅式:xml配置,java代码初始化
xml配置:
<bean id="taskExecutor" class="org.urrent.ThreadPoolTaskExecutor">
<property name="corePoolSize" value="5" />
<property name="keepAliveSeconds" value="200" />
<property name="maxPoolSize" value="10" />
<property name="queueCapacity" value="20" />
<property name="rejectedExecutionHandler">
<bean class="urrent.ThreadPoolExecutor$CallerRunsPolicy" />
</property>
</bean>
看过上⾯的内容,读者应该很清楚上⾯的⼀些参数代表的意思了吧。笔者在这⾥不⼀⼀去解释了。
1 2 3 4 5 6 7 8 9 10 11 12public MyThreadPoolTaskExecutor {
@Autowired
private ThreadPoolTaskExecutor taskExecutor;
 private void test(){
  ute(new Runnable(){
    @Override
    public void run() {
     //执⾏的代码
    }});
  }
}
Java代码初始化:1
2 3 4 5 6 7 8 9 10 11 12 13 14 15private void test2(){
  ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
  executor.setCorePoolSize(10);
  executor.setMaxPoolSize(15);
  executor.setKeepAliveSeconds(1);
  executor.setQueueCapacity(5);
  executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());  executor.initialize();
  ute(new Runnable(){
    @Override
    public void run() {
      //执⾏的代码
    }
  });
}
常⽤参数总结:
关于Java线程池的参数设置:线程池是Java多线程⾥开发⾥的重要内容,使⽤难度不⼤,但如何⽤好就要明⽩参数的含义和如何去设置。⼲货⾥的内容⼤多是参考别⼈的,加⼊了⼀些知识点的扩充和看法。希望能对多线程开发学习的童鞋有些启发和帮助。
⼀、ThreadPoolExecutor的重要参数
1、corePoolSize:核⼼线程数
* 核⼼线程会⼀直存活,及时没有任务需要执⾏
* 当线程数⼩于核⼼线程数时,即使有线程空闲,线程池也会优先创建新线程处理
* 设置allowCoreThreadTimeout=true(默认false)时,核⼼线程会超时关闭
2、queueCapacity:任务队列容量(阻塞队列)
* 当核⼼线程数达到最⼤时,新任务会放在队列中排队等待执⾏
3、maxPoolSize:最⼤线程数
* 当线程数>=corePoolSize,且任务队列已满时。线程池会创建新线程来处理任务
* 当线程数=maxPoolSize,且任务队列已满时,线程池会拒绝处理任务⽽抛出异常
4、 keepAliveTime:线程空闲时间
* 当线程空闲时间达到keepAliveTime时,线程会退出,直到线程数量=corePoolSize
* 如果allowCoreThreadTimeout=true,则会直到线程数量=0

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。