Java多线程和线程池(转)

1.为何要使用线程池html

在java中,若是每一个请求到达就建立一个新线程,开销是至关大的。在实际使用中,服务器在建立和销毁线程上花费的时间和消耗的系统资源都至关大,甚至可能要比在处理实际的用户请求的时间和资源要多的多。除了建立和销毁线程的开销以外,活动的线程也须要消耗系统资源。若是在一个jvm里建立太多的线程,可能会使系统因为过分消耗内存或“切换过分”而致使系统资源不足。为了防止资源不足,服务器应用程序须要采起一些办法来限制任何给定时刻处理的请求数目,尽量减小建立和销毁线程的次数,特别是一些资源耗费比较大的线程的建立和销毁,尽可能利 
用已有对象来进行服务,这就是“池化资源”技术产生的缘由。
java

线程池主要用来解决线程生命周期开销问题和资源不足问题。经过对多个任务重复使用线程,线程建立的开销就被分摊到了多个任务上了,并且因为在请求到达时线程已经存在,因此消除了线程建立所带来的延迟。这样,就能够当即为请求服务,使用应用程序响应更快。另外,经过适当的调整线程中的线程数目能够防止出现资源不足的状况。web

2.线程池的组成部分spring

一个比较简单的线程池至少应包含线程池管理器、工做线程、任务列队、任务接口等部分。其中线程池管理器的做用是建立、销毁并管理线程池,将工做线程放入线程池中;工做线程是一个能够循环执行任务的线程,在没有任务是进行等待;任务列队的做用是提供一种缓冲机制,将没有处理的任务放在任务列队中;任务接口是每一个任务必须实现的接口,主要用来规定任务的入口、任务执行完后的收尾工做、任务的执行状态等,工做线程经过该接口调度任务的执行。服务器

线程池管理器至少有下列功能:建立线程池,销毁线程池,添加新任务。jvm

工做线程是一个能够循环执行任务的线程,在没有任务时将等待。this

任务接口是为全部任务提供统一的接口,以便工做线程处理。任务接口主要规定了任务的入口,任务执行完后的收尾工做,任务的执行状态等。spa

3.线程池适合应用的场合.net

当一个服务器接受到大量短小线程的请求时,使用线程池技术是很是合适的,它能够大大减小线程的建立和销毁次数,提升服务器的工做效率。可是线程要求的运动时间比较长,即线程的运行时间比…….线程

以上信息来自以下文章:http://www.blogjava.net/stevenjohn/archive/2011/12/12/366161.html

1、Java自带线程池

先看看Java自带线程池的例子,开启5个线程打印字符串List:

package com.luo.test;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class ThreadTest {

    public static void main(String[] args) {

        List<String> strList = new ArrayList<String>();
        for (int i = 0; i < 100; i++) {
            strList.add("String" + i);
        }
        int threadNum = strList.size() < 5 ? strList.size() : 5;
        ThreadPoolExecutor executor = new ThreadPoolExecutor(2, threadNum, 300,
                TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(3),
                new ThreadPoolExecutor.CallerRunsPolicy());
        for (int i = 0; i < threadNum; i++) {
            executor.execute(new PrintStringThread(i,strList,threadNum));
        }
        executor.shutdown();
    }
}

class PrintStringThread implements Runnable {

    private int num;

    private List<String> strList;

    private int threadNum;

    public PrintStringThread(int num, List<String> strList, int threadNum) {
        this.num = num;
        this.strList = strList;
        this.threadNum = threadNum;
    }

    public void run() {
        int length = 0;
        for(String str : strList){
            if (length % threadNum == num) {
                System.out.println("线程编号:" + num + ",字符串:" + str);
            }
            length ++;
        }
    }
}
 

Java自带线程池构造方法

ThreadPoolExecutor(int corePoolSize, 
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue
RejectedExecutionHandler handler)

corePoolSize: 线程池维护线程的最少线程数,也是核心线程数,包括空闲线程
maximumPoolSize: 线程池维护线程的最大线程数
keepAliveTime: 线程池维护线程所容许的空闲时间
unit: 程池维护线程所容许的空闲时间的单位
workQueue: 线程池所使用的缓冲队列
handler: 线程池对拒绝任务的处理策略

当一个任务经过execute(Runnable)方法欲添加到线程池时:
1、 若是此时线程池中的数量小于corePoolSize,即便线程池中的线程都处于空闲状态,也要建立新的线程来处理被添加的任务。
2、 若是此时线程池中的数量等于 corePoolSize,可是缓冲队列 workQueue未满,那么任务被放入缓冲队列。
3、若是此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,而且线程池中的数量小于maximumPoolSize,建新的线程来处理被添加的任务。
4、 若是此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,而且线程池中的数量等于maximumPoolSize,那么经过 handler所指定的策略来处理此任务。也就是:处理任务的优先级为:核心线程corePoolSize、任务队列workQueue、最大线程 maximumPoolSize,若是三者都满了,使用handler处理被拒绝的任务。
五、 当线程池中的线程数量大于 corePoolSize时,若是某线程空闲时间超过keepAliveTime,线程将被终止。这样,线程池能够动态的调整池中的线程数。
 

事实上上面的例子代码写得有不足之处,若是你看出不足之处,说明你理解了线程池。不然能够多看几遍哦。

2、Spring线程池配置

3.一、直接调用

ThreadPoolTaskExecutor poolTaskExecutor = new ThreadPoolTaskExecutor();  
//线程池所使用的缓冲队列  
poolTaskExecutor.setQueueCapacity(200);  
//线程池维护线程的最少数量  
poolTaskExecutor.setCorePoolSize(5);  
//线程池维护线程的最大数量  
poolTaskExecutor.setMaxPoolSize(1000);  
//线程池维护线程所容许的空闲时间  
poolTaskExecutor.setKeepAliveSeconds(30000);  
poolTaskExecutor.initialize(); 

 

3.二、经过配置文件

 
<bean id="poolTaskExecutor"      class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
   <!-- 核心线程数,默认为1 -->
   <property name="corePoolSize" value="5" />
   <!-- 最大线程数,默认为Integer.MAX_VALUE -->
   <property name="maxPoolSize" value="50" />
   <!-- 队列最大长度,通常须要设置值>=notifyScheduledMainExecutor.maxNum;默认为Integer.MAX_VALUE -->
   <property name="queueCapacity" value="2000" />
   <!-- 线程池维护线程所容许的空闲时间,默认为60s -->
   <property name="keepAliveSeconds" value="100" />
   <!-- 线程池对拒绝任务(无线程可用)的处理策略,目前只支持AbortPolicy、CallerRunsPolicy;默认为后者 -->
   <property name="rejectedExecutionHandler">
       <!-- AbortPolicy:直接抛出java.util.concurrent.RejectedExecutionException异常 -->
       <!-- CallerRunsPolicy:主线程直接执行该任务,执行完以后尝试添加下一个任务到线程池中,能够有效下降向线程池内添加任务的速度 -->
       <!-- DiscardOldestPolicy:抛弃旧的任务、暂不支持;会致使被丢弃的任务没法再次被执行 -->
       <!-- DiscardPolicy:抛弃当前任务、暂不支持;会致使被丢弃的任务没法再次被执行 -->
       <bean class="java.util.concurrent.ThreadPoolExecutor$CallerRunsPolicy" />
   </property>
</bean>
相关文章
相关标签/搜索