老汉谈——线程池原理

线程池

JDK1.8官方介绍:

Thread pools address two different problems: they usually provide improved performance when executing large numbers of asynchronous tasks, due to reduced per-task invocation overhead, and they provide a means of bounding and managing the resources, including threads, consumed when executing a collection of tasks. Each ThreadPoolExecutor also maintains some basic statistics, such as the number of completed tasks.

线程池解决了两个问题:它们通常在执行大量异步任务时提供改进性能问题,由于减少了每个任务的资源开销,他们提供边界和管理资源的手段,包括线程,消费在执行任务的集合。每个ThreadPoolExecutor 维持一些基本的统计数据,比如完成任务数量。

线程池的原理

  • 线程池本身是不创建和启动线程的,只有任务到达时才会,即当一个任务提交到线程池时,就会创建一个线程。但可以重写动态使用方法prestartCoreThread()或prestartCoreAllThread()。
  • 当线程数没有达到核心线程数corePoolSize时,就会创建一个新的线程,不需要排队。当线程数大于核心线程数corePoolSize时,就会放到workerQueue任务队列里等待。
  • 当核心线程数小于等于线程总数maximunPoolSize时,如果队列中有等待的线程,则线程池会用空余的线程来执行队列的线程;否则,线程池就会采用拒绝策略来终止新的任务。
  • 如果某个线程会话时间超出保持会话时间keepAliveTime时,就会终止当前线程任务,然后加入新的线程任务。可以使用setKeepAliveTime(long, java.util.concurrent.TimeUnit)动态改变参数。一般来说,这个活动策略是已经超出了corePoolSize的线程时才应用。但只要keepAliveTime非0时,就可以通过allowCoreThreadTimeOut(true)方法,使超时策略应用在核心线程中。

任务排队

-直接提交:工作队列WorkQueue默认是SychronousQueue。它继承了AbstractQueue,实现了BlockingQueue。他的处理任务容量是无边界的。
当运行的线程数大于或等于核心线程corePoolSize时,才会加入队列,但直接提交是同步阻塞的。从下图的工作原理可以看出,直接提交maximunPoolSize最好无限大即无容量大小。

/**

- Creates a {@code SynchronousQueue} with nonfair access policy. 
  */ 
  public SynchronousQueue() { 
  this(false); 
  }

/**

- Creates a {@code SynchronousQueue} with the specified fairness policy. 
  *
- @param fair if true, waiting threads contend in FIFO order for
- access; otherwise the order is unspecified. 
  */ 
  public SynchronousQueue(boolean fair) { //fair 公平性标识 
  // 公平性TrasferQueue、 非公平行TransferStack 
  transferer = fair ? new TransferQueue() : new TransferStack(); 
  }

线程池类:ThreadPoolExecutor
应用场景:交换任工作,生产者的线程消费和消费者的线程同步传递消息、时间或任务。简单的说,任务2必须依赖于任务1的信息,
这里写图片描述
-无界队列:LinkedBlockingQueue。它保证所有的超出corePoolSize的线程都放入队列里。这样创建的线程不会超出corePoolSize.,因此maximumPoolSize值就无效了。
线程池类:newFixedThreadPool

- Creates a {@code LinkedBlockingQueue} with a capacity of
- {@link Integer#MAX_VALUE}. 
  */ 
  public LinkedBlockingQueue() { 
  this(Integer.MAX_VALUE); 
  }

/**
- Creates a {@code LinkedBlockingQueue} with the given (fixed) capacity. 
  *
- @param capacity the capacity of this queue
- @throws IllegalArgumentException if {@code capacity} is not greater
- than zero 
  */ 
  public LinkedBlockingQueue(int capacity) { 
  if (capacity <= 0) throw new IllegalArgumentException(); 
  this.capacity = capacity; 
  last = head = new Node(null); 
  }

/**
- Creates a {@code LinkedBlockingQueue} with a capacity of
- {@link Integer#MAX_VALUE}, initially containing the elements of the
- given collection,
- added in traversal order of the collection's iterator. 
  *
- @param c the collection of elements to initially contain
- @throws NullPointerException if the specified collection or any
- of its elements are null 
  */ 
  public LinkedBlockingQueue(Collection c) { 
  this(Integer.MAX_VALUE); 
  final ReentrantLock putLock = this.putLock; 
  putLock.lock(); // Never contended, but necessary for visibility 
  try { 
  int n = 0; 
  for (E e : c) { 
  if (e == null) 
  throw new NullPointerException(); 
  if (n == capacity) 
  throw new IllegalStateException("Queue full"); 
  enqueue(new Node(e)); 
  ++n; 
  } 
  count.set(n); 
  } finally { 
  putLock.unlock(); 
  } 
  }

应用场景:适合任务之间互不影响
这里写图片描述
-有界队列:ArrayBlockingQueue。这是最复杂的一种。不推荐使用。当使用有限的MaximumPoolSize时,有界队列可以防止资源耗尽,但可能很难控制与调整。队列的容量是有限的。
一般使用大池小列或小池大列,前者会增加CPU使用率,但遇到不可接受的调度开销,也会降低吞吐量;后者会减少CPU使用率、操作系统资源和上下文的切换,但可能导致人工来降低吞吐量。

/**

- Creates an {@code ArrayBlockingQueue} with the given (fixed)
- capacity and default access policy. 
  *
- @param capacity the capacity of this queue
- @throws IllegalArgumentException if {@code capacity < 1} 
  */ 
  public ArrayBlockingQueue(int capacity) { 
  this(capacity, false); 
  }

/**

- Creates an {@code ArrayBlockingQueue} with the given (fixed)
- capacity and the specified access policy. 
  *
- @param capacity the capacity of this queue
- @param fair if {@code true} then queue accesses for threads blocked
- on insertion or removal, are processed in FIFO order;
- if {@code false} the access order is unspecified.
- @throws IllegalArgumentException if {@code capacity < 1} 
  */ 
  public ArrayBlockingQueue(int capacity, boolean fair) { 
  if (capacity <= 0) 
  throw new IllegalArgumentException(); 
  this.items = new Object[capacity]; 
  lock = new ReentrantLock(fair); 
  notEmpty = lock.newCondition(); 
  notFull = lock.newCondition(); 
  }

public ArrayBlockingQueue(int capacity, boolean fair, 
Collection c) { 
this(capacity, fair);

final ReentrantLock lock = this.lock;
lock.lock(); // Lock only for visibility, not mutual exclusion
try {
    int i = 0;
    try {
        for (E e : c) {
            checkNotNull(e);
            items[i++] = e;
        }
    } catch (ArrayIndexOutOfBoundsException ex) {
        throw new IllegalArgumentException();
    }
    count = i;
    putIndex = (i == capacity) ? 0 : i;
} finally {
    lock.unlock();
}

}

从上可以看出:有界队列ArrayBlockingQueue和无界队列LinkedBlockingQueue都是使用ReentrantLock重入锁,而同步队列sychoronousQueue是使用公平性TransferQueue和非共性TransferStack,即转移数据队列和转移数据栈,从数据结构便知数据的顺序。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值