当前位置:文档之家› 线程池的管理和超时线程的实现

线程池的管理和超时线程的实现

线程池的管理和超时线程的实现
线程池的管理和超时线程的实现

在什么情况下使用线程池?

1.单个任务处理的时间比较短

2.将需处理的任务的数量大

使用线程池的好处:

1.减少在创建和销毁线程上所花的时间以及系统资源的开销

2.如不使用线程池,有可能造成系统创建大量线程而导致消耗完系统内存以及”过度切换”。

下面是一个线程池例子,经测试绝对可行:

包结构

src

test

TestThreadPool 测试类

thread

ThreadPool 线程池类

WorkThread 工作线程类

TaskMonitorThread 任务监测线程类

TaskTimeOutThread 任务超时监测线程类

task

TaskManager 任务管理器

WorkTask 任务接口

WorkTaskImp 正常任务类

WorkTaskAImp 异常任务类

WorkTaskBImp 超时任务类

event

AbstractEvent 任务事件类

BeginTaskEvent 任务执行开始事件类

EndTaskEvent 任务执行结束事件类

TaskRunTime 任务运行时间类

TaskTimeOutEvent 任务执行超时事件类

源码:

package test;

import task.TaskManager;

import task.WorkTask;

import task.WorkTaskAImp;

import task.WorkTaskBImp;

import task.WorkTaskImp;

import thread.ThreadPool;

/**

* 线程池测试类,测试功能如下:

* 1、测试线程池创建功能

* 2、测试处理并发请求功能

* 3、测试关闭功能

**/

public class TestThreadPool {

public static void main(String[] args){

//创建线程池,开启处理请求服务

final int threadCount=10;

ThreadPool pool=ThreadPool.getInstance();

pool.init(threadCount);

//接收客户端请求

WorkTask task1=new WorkTaskBImp("执行超时任务...");

TaskManager.addTask(task1);

final int requestCount=20;

for(int i=0;i

WorkTask task=new WorkTaskImp("执行第"+i+"个增加用户操作...");

TaskManager.addTask(task);

}

WorkTask task2=new WorkTaskBImp("执行超时任务...");

TaskManager.addTask(task2);

for(int i=0;i

WorkTask task=new WorkTaskAImp("执行第"+i+"个修改用户异常操作...");

TaskManager.addTask(task);

}

for(int i=0;i

WorkTask task=new WorkTaskImp("执行第"+i+"个删除用户操作...");

TaskManager.addTask(task);

}

//关闭线程池

try {

Thread.sleep(2000);//为了显示处理请求效果

pool.close();

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

package thread;

import java.util.ArrayList;

import java.util.List;

import java.util.Vector;

import event.BeginTaskEvent;

import event.EndTaskEvent;

import task.TaskManager;

/**

* 线程池类,功能如下:

* 1、初始化线程池

* 2、获取空闲线程

* 3、任务运行,注册超时监测

* 4、任务结束,注销超时监测

* 5、关闭线程池

*/

public class ThreadPool {

private int threadcount;

private int GetIdleThreadPollTime=50;//获取空闲线程轮询间隔时间,可配置

private static ThreadPool pool=new ThreadPool();//线程实例

private Vector threadlist=new Vector();//工作线程列表private TaskMonitorThread mainThread;//任务监测线程

private TaskTimeOutThread timeThread; //任务超时线程

private boolean StopGetIdleThread=false;

//单例模式

private ThreadPool(){

}

public static synchronized ThreadPool getInstance(){

return pool;

}

private void stopGetIdleThread(){

StopGetIdleThread = true;

}

//初始化线程池

public void init(int count){

System.out.println("开始初始化线程池...");

threadcount=count;

for(int i=0;i

WorkThread t=new WorkThread(new Integer(i));

threadlist.add(t);

t.start();

}

mainThread=new TaskMonitorThread(pool);

mainThread.start();

timeThread=new TaskTimeOutThread(pool);

timeThread.start();

System.out.println("结束初始化线程池...");

}

//获取空闲线程

public WorkThread getIdleThread(){

while(true){

if (StopGetIdleThread) return null;

synchronized(threadlist){

for(int i=0;i

WorkThread t=(WorkThread)threadlist.get(i);

if (t.getMyState().equals(WorkThread.IDlESTATE)){

return t;

}

}

}

try {

Thread.sleep(GetIdleThreadPollTime);//放弃CPU,若干时间后重新获取空闲线程

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

//任务运行,注册监测

public void beginTaskRun(BeginTaskEvent begin){

timeThread.beginTaskRun(begin);

}

//任务结束,注销监视

public void endTaskRun(EndTaskEvent end){

timeThread.endTaskRun(end);

}

//从工作线程表中移除线程

public void removeWorkThread(WorkThread t){

threadlist.remove(t);

}

//添加新的线程

public void addWorkThread(){

synchronized(threadlist){

WorkThread t=new WorkThread(new Integer(++threadcount));

threadlist.add(t);

t.start();

}

}

//关闭线程池

public void close(){

//停止获取空闲线程

stopGetIdleThread();

//关闭任务监测线程,不再接收请求

mainThread.kill();

//关闭超时监测线程

timeThread.kill();

//关闭工作线程,不再处理任务

for(int i=0;i

WorkThread t=(WorkThread)threadlist.get(i);

t.kill();

}

}

}

package thread;

import task.WorkTask;

import event.BeginTaskEvent;

import event.EndTaskEvent;

/**

* 工作线程类,功能如下:

* 1、执行业务方法,业务参数可动态设置

* 2、自身状态可设置、可获取

* 3、自我唤醒功能

* 4、自杀功能

*/

public final class WorkThread extends Thread{

private boolean shutdown=false;

private String info; //业务参数

private Object threadKey;//线程标识

private Object lock=new Object();//锁对象

private String state; //线程状态

private int waitExecFinishPollTime=500;//关闭线程时的轮询等待时间,可配置public static final String CREATESTATE="1";//创建状态

public static final String RUNSTATE="2"; //运行状态

public static final String IDlESTA TE="3"; //空闲状态

private WorkTask nowTask; //当前任务

//获取线程标识key

public Object getThreadKey() {

return threadKey;

}

//设置线程的任务

public void setWorkTask(WorkTask task){

this.nowTask=task;

}

//设置是否关闭线程

private void setShutdown(boolean shutdown) {

this.shutdown = shutdown;

}

//设置线程状态

private void setMyState(String state){

this.state=state;

}

//获取线程状态

public String getMyState(){

return state;

}

public WorkThread(Object key){

System.out.println("正在创建工作线程...线程编号"+key.toString());

this.threadKey=key;

this.state=CREATESTATE;

}

@Override

public synchronized void start() {

// TODO Auto-generated method stub

super.start();

setMyState(RUNSTA TE);

}

public void run(){

while(true){

try {

setMyState(IDlESTA TE);

synchronized(this){

wait(); /*开始等待,直至被激活*/

}

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

if (shutdown) break;

try{

new BeginTaskEvent(this,Thread.currentThread(),nowTask).execute();

nowTask.execute();//执行业务

new EndTaskEvent(this,Thread.currentThread(),nowTask).execute();

}catch(Exception e){

new EndTaskEvent(this,Thread.currentThread(),nowTask).execute();

System.out.println(e.getMessage());

}

}

}

//重新激活线程

public void activate(){

synchronized(this){

setMyState(RUNSTA TE);

notify();

}

}

//关闭线程

public void kill(){

synchronized(this){

if (this.getMyState().equals(IDlESTATE)){//如果线程处于空闲状态,则直接关掉System.out.println("正在关闭工作线程...线程编号"+threadKey.toString());

this.setShutdown(true);

this.activate();

}else if (this.getMyState().equals(RUNSTATE)){//如果线程处于运行状态,则执行完后再关掉

System.out.println("正在等待线程执行业务完成...工作线程编号"+threadKey.toString());

while(this.getMyState().equals(RUNSTATE)){

try {

Thread.sleep(waitExecFinishPollTime);//放弃CPU,若干时间后再检查线程状态

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

System.out.println("正在关闭工作线程...线程编号"+threadKey.toString());

this.setShutdown(true);

this.activate();

}

}

}

}

package thread;

import task.TaskManager;

import task.WorkTask;

/**

* 任务检测线程类

* 1、自杀功能

*/

public final class TaskMonitorThread extends Thread {

private ThreadPool threadPool;

private int GetWorkTaskPollTime=10;//监测任务轮询时间,可配置

private boolean shutdown=false;

public TaskMonitorThread(ThreadPool pool){

System.out.println("正在创建任务监测线程...");

this.threadPool=pool;

}

private void setShutDown(boolean b){

this.shutdown=b;

}

@Override

public void run() {

// TODO Auto-generated method stub

while(true){

if (shutdown) break;

WorkTask task=TaskManager.getWorkTask();//看是否有任务请求

if (task==null){

try {

Thread.sleep(GetWorkTaskPollTime);

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}else{

WorkThread t=threadPool.getIdleThread();//获取空闲线程

if (t==null) break;

t.setWorkTask(task);//设置线程任务

task.setTaskThreadKey(t.getThreadKey());//为了显示任务当前线程

t.activate();//激活空闲线程

try {

Thread.sleep(GetWorkTaskPollTime);

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

}

//关闭线程

public void kill(){

System.out.println("正在关闭任务监测线程...");

this.setShutDown(true);

}

}

package thread;

import java.util.Vector;

import event.BeginTaskEvent;

import event.EndTaskEvent;

import event.TaskRunTime;

import event.TaskTimeOutEvent;

/**

* 任务超时监测线程类

* 1、任务开始注册

* 2、任务完成注销

* 3、自杀功能

*/

public class TaskTimeOutThread extends Thread {

private ThreadPool pool;

private boolean shutdown=false;

private Vector taskruntimelist=new Vector();//运行任务列表

private int pollTime=500; //轮询时间

private int TaskOutTime=2000; //任务过时时间

public TaskTimeOutThread(ThreadPool pool){

this.pool=pool;

}

@Override

public void run() {

// TODO Auto-generated method stub

while(!shutdown){

synchronized(taskruntimelist){

for(int i=0;i

TaskRunTime t=(TaskRunTime) taskruntimelist.get(i);

if (t.checkRunTimeOut(TaskOutTime)){

taskruntimelist.remove(i);

new TaskTimeOutEvent(t.getEvent()).execute();

break;

}

}

}

try {

sleep(pollTime);

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

//任务运行,开始监测

public void beginTaskRun(BeginTaskEvent begin){

taskruntimelist.add(new TaskRunTime(begin));

}

//任务正常结束

public void endTaskRun(EndTaskEvent end){

synchronized(taskruntimelist){

for(int i=0;i

BeginTaskEvent begin=((TaskRunTime) taskruntimelist.get(i)).getEvent();

if (begin.equals(end)){

taskruntimelist.remove(i);

break;

}

}

}

}

//自杀

public void kill(){

System.out.println("正在关闭超时监测线程...");

while(taskruntimelist.size()>0){

try {

Thread.sleep(pollTime);

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

shutdown=true;

}

}

package task;

import java.util.ArrayList;

import java.util.List;

/**

* 任务管理器

* 1、添加任务

* 2、监测是否有新任务

*/

public class TaskManager {

private static List taskQueue=new ArrayList(); //任务队列private TaskManager(){

}

//添加任务

public synchronized static void addTask(WorkTask task){

taskQueue.add(task);

}

//判断是否有任务未执行

public synchronized static WorkTask getWorkTask(){

if (taskQueue.size()>0){

return (WorkTask)taskQueue.remove(0);

}else

return null;

}

}

package task;

/**

* 任务接口

* 继承它来定义自己具体的工作任务

*/

public interface WorkTask {

void execute() throws Exception; //执行工作任务

void setTaskThreadKey(Object key);//设置任务线程编号

}

package task;

/**

* 任务类1

* 正常执行的工作任务

*/

public class WorkTaskImp implements WorkTask {

protected String param;

protected Object threadkey; //为了显示执行线程编号

protected final int TaskExecTime=500; //任务执行时间

public void execute() throws Exception {

// TODO Auto-generated method stub

System.out.println(param+"工作线程编号"+threadkey.toString());

Thread.sleep(TaskExecTime);

}

public WorkTaskImp(String param){

this.param=param;

}

public void setTaskThreadKey(Object key){

this.threadkey=key;

}

public String toString(){

return param+"工作线程编号"+threadkey.toString();

}

}

package task;

/**

* 任务类2

* 执行报异常的工作任务

*/

public class WorkTaskAImp extends WorkTaskImp{

public WorkTaskAImp(String param) {

super(param);

// TODO Auto-generated constructor stub

}

public void execute() throws Exception {

// TODO Auto-generated method stub

throw new Exception("运行WorkTaskAImp任务时出错");

}

}

package task;

* 任务类3

* 执行超时的工作任务

*/

public class WorkTaskBImp extends WorkTaskImp{

public WorkTaskBImp(String param) {

super(param);

// TODO Auto-generated constructor stub

}

public void execute() throws Exception {

// TODO Auto-generated method stub

System.out.println("正在"+param);

Thread.sleep(50000); //随便定义

}

}

package event;

import task.WorkTask;

import thread.WorkThread;

/*

*任务抽象事件

*/

public abstract class AbstractEvent {

protected WorkThread workthread;

protected Thread nowthread;

protected WorkTask nowtask;

//事件触发

public synchronized void execute(){};

@Override

public boolean equals(Object obj) {

// TODO Auto-generated method stub

AbstractEvent other=(AbstractEvent)obj;

return this.workthread==other.workthread&&this.nowtask==this.nowtask;

};

}

package event;

import task.WorkTask;

import thread.ThreadPool;

import thread.WorkThread;

/*

* 任务开始运行事件

*/

public class BeginTaskEvent extends AbstractEvent{

public BeginTaskEvent(WorkThread workthread,Thread nowthread,WorkTask task){ this.workthread=workthread;

this.nowthread=nowthread;

this.nowtask=task;

}

@Override

public void execute() {

// TODO Auto-generated method stub

ThreadPool pool=ThreadPool.getInstance();

pool.beginTaskRun(this);

}

}

package event;

import task.WorkTask;

import thread.ThreadPool;

import thread.WorkThread;

/*

* 任务运行结束事件

*/

public class EndTaskEvent extends AbstractEvent {

public EndTaskEvent(WorkThread workthread,Thread nowthread,WorkTask task){ this.workthread=workthread;

this.nowthread=nowthread;

this.nowtask=task;

}

@Override

public void execute() {

// TODO Auto-generated method stub

ThreadPool pool=ThreadPool.getInstance();

pool.endTaskRun(this);

}

}

package event;

/*

* 任务运行时间类

*/

public class TaskRunTime {

private long begintime;

private long endtime;

private BeginTaskEvent event;

public TaskRunTime(BeginTaskEvent event){

this.event=event;

this.begintime=System.currentTimeMillis();

this.endtime=this.begintime;

}

public BeginTaskEvent getEvent() {

return event;

}

//检查是否超时

public boolean checkRunTimeOut(long maxtime){ endtime=System.currentTimeMillis();

long cha=endtime-begintime;

return cha>=maxtime;

}

}

package event;

import task.WorkTask;

import thread.ThreadPool;

import thread.WorkThread;

/*

* 任务超时事件

*/

public class TaskTimeOutEvent {

private AbstractEvent event;

public TaskTimeOutEvent(AbstractEvent event){

this.event=event;

}

@SuppressWarnings("deprecation")

public void execute() {

// TODO Auto-generated method stub

ThreadPool pool=ThreadPool.getInstance();

pool.addWorkThread();

pool.removeWorkThread(event.workthread);

Object obj=event.workthread.getThreadKey();

System.out.println("正在停止工作超时线程...线程编号"+obj);

event.nowthread.stop();

}

}

运行结果

开始初始化线程池...

正在创建工作线程...线程编号0

正在创建工作线程...线程编号1

正在创建工作线程...线程编号2

正在创建工作线程...线程编号3

正在创建工作线程...线程编号4

正在创建工作线程...线程编号5

正在创建工作线程...线程编号6

正在创建工作线程...线程编号7

正在创建工作线程...线程编号8

正在创建工作线程...线程编号9

正在创建任务监测线程...

结束初始化线程池...

正在执行超时任务1...

执行第0个增加用户操作...工作线程编号1

执行第1个增加用户操作...工作线程编号2

执行第2个增加用户操作...工作线程编号3

执行第3个增加用户操作...工作线程编号4

执行第4个增加用户操作...工作线程编号5

执行第5个增加用户操作...工作线程编号6

执行第6个增加用户操作...工作线程编号7

执行第7个增加用户操作...工作线程编号8

执行第8个增加用户操作...工作线程编号9

执行第9个增加用户操作...工作线程编号1

执行第10个增加用户操作...工作线程编号2

执行第11个增加用户操作...工作线程编号3

执行第12个增加用户操作...工作线程编号4

执行第13个增加用户操作...工作线程编号5

执行第14个增加用户操作...工作线程编号6

执行第15个增加用户操作...工作线程编号7

执行第16个增加用户操作...工作线程编号8

执行第17个增加用户操作...工作线程编号9

执行第18个增加用户操作...工作线程编号1 执行第19个增加用户操作...工作线程编号2 正在执行超时任务2...

运行WorkTaskAImp任务时出错

运行WorkTaskAImp任务时出错

运行WorkTaskAImp任务时出错

运行WorkTaskAImp任务时出错

运行WorkTaskAImp任务时出错

运行WorkTaskAImp任务时出错

运行WorkTaskAImp任务时出错

运行WorkTaskAImp任务时出错

运行WorkTaskAImp任务时出错

运行WorkTaskAImp任务时出错

运行WorkTaskAImp任务时出错

运行WorkTaskAImp任务时出错

运行WorkTaskAImp任务时出错

运行WorkTaskAImp任务时出错

运行WorkTaskAImp任务时出错

运行WorkTaskAImp任务时出错

运行WorkTaskAImp任务时出错

运行WorkTaskAImp任务时出错

运行WorkTaskAImp任务时出错

运行WorkTaskAImp任务时出错

执行第0个删除用户操作...工作线程编号4 执行第1个删除用户操作...工作线程编号5 执行第2个删除用户操作...工作线程编号6 执行第3个删除用户操作...工作线程编号7 执行第4个删除用户操作...工作线程编号8 执行第5个删除用户操作...工作线程编号9 执行第6个删除用户操作...工作线程编号1 执行第7个删除用户操作...工作线程编号2 执行第8个删除用户操作...工作线程编号4 执行第9个删除用户操作...工作线程编号5 执行第10个删除用户操作...工作线程编号6 执行第11个删除用户操作...工作线程编号7 执行第12个删除用户操作...工作线程编号8 执行第13个删除用户操作...工作线程编号9 正在关闭任务监测线程...

正在关闭超时监测线程...

正在创建工作线程...线程编号11

正在停止工作超时线程...线程编号0

正在创建工作线程...线程编号12

正在停止工作超时线程...线程编号3

正在关闭工作线程...线程编号1

正在关闭工作线程...线程编号2 正在关闭工作线程...线程编号4 正在关闭工作线程...线程编号5 正在关闭工作线程...线程编号6 正在关闭工作线程...线程编号7 正在关闭工作线程...线程编号8 正在关闭工作线程...线程编号9 正在关闭工作线程...线程编号11 正在关闭工作线程...线程编号12

JAVA线程池原理333

在什么情况下使用线程池? 1.单个任务处理的时间比较短 2.将需处理的任务的数量大 使用线程池的好处: 1.减少在创建和销毁线程上所花的时间以及系统资源的开销 2.如不使用线程池,有可能造成系统创建大量线程而导致消耗完系统内存以及”过度切换”。 线程池工作原理:

线程池为线程生命周期开销问题和资源不足问题提供了解决方案。通过对多个任务重用线程,线程创建的开销被分摊到了多个任务上。其好处是,因为在请求到达时线程已经存在,所以无意中也消除了线程创建所带来的延迟。这样,就可以立即为请求服务,使应用程序响应更快。而且,通过适当地调整线程池中的线程数目,也就是当请求的数目超过某个阈值时,就强制其它任何新到的请求一直等待,直到获得一个线程来处理为止,从而可以防止资源不足。 线程池的替代方案 线程池远不是服务器应用程序内使用多线程的唯一方法。如同上面所提到的,有时,为每个新任务生成一个新线程是十分明智的。然而,如果任务创建过于频繁而任务的平均处理时间过短,那么为每个任务生成一个新线程将会导致性能问题。 另一个常见的线程模型是为某一类型的任务分配一个后台线程与任务队列。AWT 和 Swing 就使用这个模型,在这个模型中有一个 GUI 事件线程,导致用户界面发生变化的所有工作都必须在该线程中执行。然而,由于只有一个 AWT 线程,因此要在 AWT 线程中执行任务可能要花费相当长时间才能完成,这是不可取的。因此,Swing 应用程序经常需要额外的工作线程,用于运行时间很长的、同 UI 有关的任务。 每个任务对应一个线程方法和单个后台线程(single-background-thread)方法在某些情形下都工作得非常理想。每个任务一个线程方法在只有少量运行时间很长的任务时工作得十分好。而只要调度可预见性不是很重要,则单个后台线程方法就工作得十分好,如低优先级后台任务就是这种情况。然而,大多数服务器应用程序都是面向处理大量的短期任务或子任务,因此往往希望具有一种能够以低开销有效地处理这些任务的机制以及一些资源管理和定时可预见性的措施。线程池提供了这些优点。 工作队列 就线程池的实际实现方式而言,术语“线程池”有些使人误解,因为线程池“明显的”实现在大多数情形下并不一定产生我们希望的结果。术语“线程池”先于Java 平台出现,因此它可能是较少面向对象方法的产物。然而,该术语仍继续广泛应用着。 虽然我们可以轻易地实现一个线程池类,其中客户机类等待一个可用线程、将任务传递给该线程以便执行、然后在任务完成时将线程归还给池,但这种方法却存在几个潜在的负面影响。例如在池为空时,会发生什么呢?试图向池线程传递任务的调用者都会发现池为空,在调用者等待一个可用的池线程时,它的线程将阻塞。我们之所以要使用后台线程的原因之一常常是为了防止正在提交的线程被阻塞。完全堵住调用者,如在线程池的“明显的”实现的情况,可以杜绝我们试图解决的问题的发生。 我们通常想要的是同一组固定的工作线程相结合的工作队列,它使用 wait() 和

解决多线程中11个常见问题

并发危险 解决多线程代码中的11 个常见的问题 Joe Duffy 本文将介绍以下内容:?基本并发概念 ?并发问题和抑制措施 ?实现安全性的模式?横切概念本文使用了以下技术: 多线程、.NET Framework 目录 数据争用 忘记同步 粒度错误 读写撕裂 无锁定重新排序 重新进入 死锁 锁保护 戳记 两步舞曲 优先级反转 实现安全性的模式 不变性 纯度 隔离 并发现象无处不在。服务器端程序长久以来都必须负责处理基本并发编程模型,而随着多核处理器的日益普及,客户端程序也将需要执行一些任务。随着并发操作的不断增加,有关确保安全的问题也浮现出来。也就是说,在面对大量逻辑并发操作和不断变化的物理硬件并行性程度时,程序必须继续保持同样级别的稳定性和可靠性。 与对应的顺序代码相比,正确设计的并发代码还必须遵循一些额外的规则。对内存的读写以及对共享资源的访问必须使用同步机制进行管制,以防发生冲突。另外,通常有必要对线程进行协调以协同完成某项工作。 这些附加要求所产生的直接结果是,可以从根本上确保线程始终保持一致并且保证其顺利向前推进。同步和协调对时间的依赖性很强,这就导致了它们具有不确定性,难于进行预测和测试。 这些属性之所以让人觉得有些困难,只是因为人们的思路还未转变过来。没有可供学习的专门API,也没有可进行复制和粘贴的代码段。实际上的确有一组基础概念需要您学习和适应。很可能随着时间的推移某些语言和库会隐藏一些概念,但如果您现在就开始执行并发操作,则不会遇到这种情况。本

文将介绍需要注意的一些较为常见的挑战,并针对您在软件中如何运用它们给出一些建议。 首先我将讨论在并发程序中经常会出错的一类问题。我把它们称为“安全隐患”,因为它们很容易发现并且后果通常比较严重。这些危险会导致您的程序因崩溃或内存问题而中断。 当从多个线程并发访问数据时会发生数据争用(或竞争条件)。特别是,在一个或多个线程写入一段数据的同时,如果有一个或多个线程也在读取这段数据,则会发生这种情况。之所以会出现这种问题,是因为Windows 程序(如C++ 和Microsoft .NET Framework 之类的程序)基本上都基于共享内存概念,进程中的所有线程均可访问驻留在同一虚拟地址空间中的数据。静态变量和堆分配可用于共享。请考虑下面这个典型的例子: static class Counter { internal static int s_curr = 0; internal static int GetNext() { return s_curr++; } } Counter 的目标可能是想为GetNext 的每个调用分发一个新的唯一数字。但是,如果程序中的两个线程同时调用GetNext,则这两个线程可能被赋予相同的数字。原因是s_curr++ 编译包括三个独立的步骤: 1.将当前值从共享的s_curr 变量读入处理器寄存器。 2.递增该寄存器。 3.将寄存器值重新写入共享s_curr 变量。 按照这种顺序执行的两个线程可能会在本地从s_curr 读取了相同的值(比如42)并将其递增到某个值(比如43),然后发布相同的结果值。这样一来,GetNext 将为这两个线程返回相同的数字,导致算法中断。虽然简单语句s_curr++ 看似不可分割,但实际却并非如此。 忘记同步 这是最简单的一种数据争用情况:同步被完全遗忘。这种争用很少有良性的情况,也就是说虽然它们是正确的,但大部分都是因为这种正确性的根基存在问题。 这种问题通常不是很明显。例如,某个对象可能是某个大型复杂对象图表的一部分,而该图表恰好可使用静态变量访问,或在创建新线程或将工作排入线程池时通过将某个对象作为闭包的一部分进行传递可变为共享图表。 当对象(图表)从私有变为共享时,一定要多加注意。这称为发布,在后面的隔离上下文中会对此加以讨论。反之称为私有化,即对象(图表)再次从共享变为私有。 对这种问题的解决方案是添加正确的同步。在计数器示例中,我可以使用简单的联锁: static class Counter { internal static volatile int s_curr = 0; internal static int GetNext() { return Interlocked.Increment(ref s_curr);

java深入理解线程池

深入研究线程池 一.什么是线程池? 线程池就是以一个或多个线程[循环执行]多个应用逻辑的线程集合. 注意这里用了线程集合的概念是我生造的,目的是为了区分执行一批应用逻辑的多个线程和 线程组的区别.关于线程组的概念请参阅基础部分. 一般而言,线程池有以下几个部分: 1.完成主要任务的一个或多个线程. 2.用于调度管理的管理线程. 3.要求执行的任务队列. 那么如果一个线程循环执行一段代码是否是线程池? 如果极端而言,应该算,但实际上循环代码应该算上一个逻辑单元.我们说最最弱化的线程池 应该是循环执行多个逻辑单元.也就是有一批要执行的任务,这些任务被独立为多个不同的执行单元.比如: int x = 0; while(true){ x ++; } 这就不能说循环中执行多个逻辑单元,因为它只是简单地对循环外部的初始变量执行++操作. 而如果已经有一个队列 ArrayList al = new ArrayList(); for(int i=0;i<10000;i++){ al.add(new AClass()); } 然后在一个线程中执行: while(al.size() != 0){ AClass a = (AClass)al.remove(0); a.businessMethod(); } 我们说这个线程就是循环执行多个逻辑单元.可以说这个线程是弱化的线程池.我们习惯上把这些相对独立的逻辑单元称为任务. 二.为什么要创建线程池? 线程池属于对象池.所有对象池都具有一个非常重要的共性,就是为了最大程度复用对象.那么 线程池的最重要的特征也就是最大程度利用线程. 从编程模型模型上说讲,在处理多任务时,每个任务一个线程是非常好的模型.如果确实可以这么做我们将可以使用编程模型更清楚,更优化.但是在实际应用中,每个任务一个线程会使用系统限入"过度切换"和"过度开销"的泥潭. 打个比方,如果可能,生活中每个人一辆房车,上面有休息,娱乐,餐饮等生活措施.而且道路交道永远不堵车,那是多么美好的梦中王国啊.可是残酷的现实告诉我们,那是不可能的.不仅每个人一辆车需要无数多的社会资源,而且地球上所能容纳的车辆总数是有限制的. 首先,创建线程本身需要额外(相对于执行任务而必须的资源)的开销.

完成端口加线程池技术实现

WinSock 异步I/O模型[5]---完成端口 - Completion Port ---------------------------------------------------------------------------- 如果你想在Windows平台上构建服务器应用,那么I/O模型是你必须考虑的。Windows操作系统提供了五种I/O模型,分别是: ■选择(select); ■异步选择(WSAAsyncSelect); ■事件选择(WSAEventSelect); ■重叠I/O(Overlapped I/O); ■完成端口(Completion Port) 。 每一种模型适用于一种特定的应用场景。程序员应该对自己的应用需求非常明确,综合考虑到程序的扩展性和可移植性等因素,作出自己的选择。 ============================================== █“完成端口”模型是迄今为止最复杂的一种 I/O 模型。但是,若一个应用程序同时需要管理很多的套接字, 那么采用这种模型,往往可以达到最佳的系统性能!但缺点是,该模型只适用于Windows NT 和 Windows 2000 以上版本的操作系统。 █因其设计的复杂性,只有在你的应用程序需要同时管理数百乃至上千个套接字的时候,而且希望随着系统内安装的CPU数量的增多, 应用程序的性能也可以线性提升,才应考虑采用“完成端口”模型。 █从本质上说,完成端口模型要求我们创建一个 Win32 完成端口对象,通过指定数量的线程, 对重叠 I/O 请求进行管理,以便为已经完成的重叠 I/O 请求提供服务。

Spring提供的线程池支持

核心提示:一旦企业应用越来越复杂时(比如,基于流程服务器的EIS),它们对相关技术也提出 了更高的要求。在使用EJB 3.0组件技术开发企业应用过程中,它们能够享受到EJB容器提供的线 程池、任务调度(@Timeout)服务。现如今,运行于Web容器的Web应用、单独的桌面应用 一旦企业应用越来越复杂时(比如,基于流程服务器的EIS),它们对相关技术也提出了更高的要求。在使用EJB 3.0组件技术开发企业应用过程中,它们能够享受到EJB容器提供的线程池、任务调度(@Timeout)服务。现如今,运行于Web容器的Web应用、单独的桌面应用也复杂到需要依赖于线程池、任务调度的这类服务,是时候实现贵族到平民的转变了。 过去,很多企业项目可能会自身实现这类底层的非功能性的服务。从Java SE 5.0开始,线程池服务(即,java.util.concurrent包)已经内置到JDK中。至于任务调度服务,其实,自从Java 2 SDK 1.3以来,Java 2就内置了用于任务调度的定时器(比如,java.util.Timer、javax.swing.Timer)。开源领域的Quartz Scheduler正是能够提供企业级任务调度服务的使能技术,而且EJB 2.x也加强了任务调度的支持。甚至,BEA同IBM合作开发了Timer and Work Manager for Application Servers技术规范(CommonJ),这是专门用来解决Java EE应用中的线程池、任务调度问题的。另外,JMX规范中也定义了javax.management.timer.TimerMBean,开发者借助于它能够实现定时JMX通知。 针对上述各种线程池、任务调度支持,Spring 2.0提供了统一的客户视图、抽象,这使得应用根本不用理会底层的具体实现和机制。本章将从分析Spring 2.0提供的线程池支持入手,并过渡到Spring 2.0对任务调度提供的支持当中,从而进入到下一章内容。 15.1 Spring提供的线程池支持 自从Spring 2.0开始,TaskExecutor接口被引入到Spring平台中,这主要受到Java SE 5.0中java.util.concurrent.Executor的影响。这一接口为各种线程池服务提供了抽象,它在统一客户视图 方面起到了最重要的作用。无论是Spring 2.0内部实现中,还是各种基于Spring的企业应用,TaskExecutor的应用随处可见,其定义如下。 public interface TaskExecutor { //异步或同步执行用户提交的任务 void execute(Runnable task); } 开发者可以通过execute(Runnable task)方法将待执行的任务提交给TaskExecutor。依据不同的TaskExecutor接口实现,这一任务会以异步或同步的方式进行。如果是同步,则调用者一直处于阻 塞状态,直到任务被执行完成。此时,调用者同目标任务的执行处于同一线程中,因此线程上下 文信息能够传播到目标任务的执行过程中。如果是异步,则一旦提交完任务,调用者即可返回, 并继续进行自身的其他操作。此时,调用者同目标任务的执行位于不同的线程中,因此线程上下 文信息很可能不能够在它们之间共享。应用要合理选择同步或异步。比如,在调用execute()期间, 如果采用Spring受管事务或Acegi提供的企业级安全性服务,则一旦同步或异步选用不当,事务

Java定时任务ScheduledThreadPoolExecutor

Timer计时器有管理任务延迟执行("如1000ms后执行任务")以及周期性执行("如每500ms执行一次该任务")。但是,Timer存在一些缺陷,因此你应该考虑使用ScheduledThreadPoolExecutor作为代替品,Timer对调度的支持是基于绝对时间,而不是相对时间的,由此任务对系统时钟的改变是敏感的;ScheduledThreadExecutor只支持相对时间。 Timer的另一个问题在于,如果TimerTask抛出未检查的异常,Timer将会产生无法预料的行为。Timer线程并不捕获异常,所以TimerTask抛出的未检查的异常会终止timer 线程。这种情况下,Timer也不会再重新恢复线程的执行了;它错误的认为整个Timer都被取消了。此时,已经被安排但尚未执行的TimerTask永远不会再执行了,新的任务也不能被调度了。 例子: packagecom.concurrent.basic; importjava.util.Timer; import java.util.TimerTask; public class TimerTest { private Timer timer = new Timer(); // 启动计时器 public void lanuchTimer() { timer.schedule(new TimerTask() { public void run() { throw new RuntimeException(); } }, 1000 * 3, 500); } // 向计时器添加一个任务 public void addOneTask() { timer.schedule(new TimerTask() { public void run() { System.out.println("hello world"); } }, 1000 * 1, 1000 * 5); }

使用 GPars 解决常见并发问题

重庆IT论坛https://www.doczj.com/doc/2d14783420.html, 在并发性时代,带有4、6 和16 个处理器核心的芯片变得很普遍,而且在不久的将来,我们会看到带有上百甚至上千个核心的芯片。这种处理能力蕴含着巨大的可能性,但对于软件开发人员来说,它也带来了挑战。最大限度地利用这些闪耀新核的需求推动了对并发性、状态管理和为两者构建的编程语言的关注热潮。 Groovy、Scala 和Clojure 等JVM 语言满足了这些需求。这三种都是较新的语言,运行于高度优化的JVM 之上,可以使用Java 1.5 中新增的强大的Java 并发库。尽管每种语言基于其原理采用不同的方法,不过它们都积极支持并发编程。 在本文中,我们将使用GPars,一种基于Groovy 的并发库,来检查模型以便解决并发性问题,比如后台处理、并行处理、状态管理和线程协调。 为何选择Groovy ?为何选择GPars ? Groovy 是运行于JVM 之上的一种动态语言。基于Java 语言,Groovy 移除了Java 代码中的大量正式语法,并添加了来自其他编程语言的有用特性。Groovy 的强大特性之一是它允许编程人员轻松创建基于Groovy 的DSL。(一个DSL 或域特定语言是一种旨在解决特定编程问题的脚本语言。参阅参考资料了解有关DSL 的更多信息。) 获取代码和工具 参阅参考资料部分下载Groovy、GPars 和本文中用到的其他工具。您可以随时下载本文的可执行代码样例。 GPars 或Groovy Parallel Systems 是一种Groovy 并发库,捕捉并发性和协调模型作为DSL。GPars 的构思源自其他语言的一些最受欢迎的并发性和协调模型,包括:?来自Java 语言的executors 和fork/join ?来自Erlang 和Scala 的actors ?来自Clojure 的agents ?来自Oz 的数据流变量 Groovy 和GPars 的结合成为展示各种并发性方法的理想之选。甚至不熟悉Groovy 的Java 开发人员也能轻松关注相关讨论,因为Groovy 的语法以Java 语言为基础。本文中的示例基于Groovy 1.7 和GPars 0.10。 回页首 后台和并行处理 一个常见的性能难题是需要等待I/O。I/O 可能涉及到从一个磁盘、一个web 服务或甚至是一名用户读取数据。当一个线程在等待I/O 的过程中被阻止时,将等待中的线程与原始执行线程分离开来将会很有用,这将使它能继续工作。由于这种等待是在后台发生的,所以我们称这种技术为后台处理。 例如,假设我们需要这样一个程序,即调用Twitter API 来找到针对若干JVM 语言的最新tweets 并将它们打印出来。Groovy 能够使用Java 库twitter4j 很容易就编写出这样的程序,如清单1 所示: 清单1. 串行读取tweets (langTweets.groovy) import twitter4j.Twitter import twitter4j.Query

精选大厂java多线程面试题50题

Java多线程50题 1)什么是线程? 线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。程序员可以通过它进行多处理器编程,你可以使用多线程对运算密集型任务提速。比如,如果一个线程完成一个任务要100毫秒,那么用十个线程完成改任务只需10毫秒。 2)线程和进程有什么区别? 线程是进程的子集,一个进程可以有很多线程,每条线程并行执行不同的任务。不同的进程使用不同的内存空间,而所有的线程共享一片相同的内存空间。别把它和栈内存搞混,每个线程都拥有单独的栈内存用来存储本地数据。更多详细信息请点击这里。 3)如何在Java中实现线程? https://www.doczj.com/doc/2d14783420.html,ng.Thread类的实例就是一个线程但是它需要调用https://www.doczj.com/doc/2d14783420.html,ng.Runnable接口来执行,由于线程类本身就是调用的 Runnable接口所以你可以继承https://www.doczj.com/doc/2d14783420.html,ng.Thread类或者直接调用Runnable接口来重写run()方法实现线程。 4)Thread类中的start()和run()方法有什么区别? 这个问题经常被问到,但还是能从此区分出面试者对Java线程模型的理解程度。start()方法被用来启动新创建的线程,而且start()内部调用了run()方法,这和直接调用run()方法的效果不一样。当你

调用run()方法的时候,只会是在原来的线程中调用,没有新的线程启动,start()方法才会启动新线程。 5)Java中Runnable和Callable有什么不同? Runnable和Callable都代表那些要在不同的线程中执行的任务。Runnable从JDK1.0开始就有了,Callable是在JDK1.5增加的。它们的主要区别是Callable的call()方法可以返回值和抛出异常,而Runnable的run()方法没有这些功能。Callable可以返回装载有计算结果的Future对象。 6)Java内存模型是什么? Java内存模型规定和指引Java程序在不同的内存架构、CPU 和操作系统间有确定性地行为。它在多线程的情况下尤其重要。 Java内存模型对一个线程所做的变动能被其它线程可见提供了保证,它们之间是先行发生关系。 ●线程内的代码能够按先后顺序执行,这被称为程序次序 规则。 ●对于同一个锁,一个解锁操作一定要发生在时间上后发 生的另一个锁定操作之前,也叫做管程锁定规则。 ●前一个对Volatile的写操作在后一个volatile的读操作之 前,也叫volatile变量规则。 ●一个线程内的任何操作必需在这个线程的start()调用之 后,也叫作线程启动规则。 ●一个线程的所有操作都会在线程终止之前,线程终止规

Tomcat线程池实现简介

Tomcat线程池实现简介 目前市场上常用的开源Java Web容器有Tomcat、Resin和Jetty。其中Resin从V3.0后需要购买才能用于商业目的,而其他两种则是纯开源的。可以分别从他们的网站上下载最新的二进制包和源代码。 作为Web容器,需要承受较高的访问量,能够同时响应不同用户的请求,能够在恶劣环境下保持较高的稳定性和健壮性。在HTTP服务器领域,Apache HTTPD的效率是最高的,也是最为稳定的,但它只能处理静态页面的请求,如果需要支持动态页面请求,则必须安装相应的插件,比如mod_perl可以处理Perl脚本,mod_python可以处理Python脚本。 上面介绍的三中Web容器,都是使用Java编写的HTTP服务器,当然他们都可以嵌到Apache 中使用,也可以独立使用。分析它们处理客户请求的方法有助于了解Java多线程和线程池的实现方法,为设计强大的多线程服务器打好基础。 Tomcat是使用最广的Java Web容器,功能强大,可扩展性强。最新版本的Tomcat(5.5.17)为了提高响应速度和效率,使用了Apache Portable Runtime(APR)作为最底层,使用了APR 中包含Socket、缓冲池等多种技术,性能也提高了。APR也是Apache HTTPD的最底层。可想而知,同属于ASF(Apache Software Foundation)中的成员,互补互用的情况还是很多的,虽然使用了不同的开发语言。 Tomcat 的线程池位于tomcat-util.jar文件中,包含了两种线程池方案。方案一:使用APR 的Pool技术,使用了JNI;方案二:使用Java实现的ThreadPool。这里介绍的是第二种。如果想了解APR的Pool技术,可以查看APR的源代码。 ThreadPool默认创建了5个线程,保存在一个200维的线程数组中,创建时就启动了这些线程,当然在没有请求时,它们都处理“等待”状态(其实就是一个while循环,不停的等待notify)。如果有请求时,空闲线程会被唤醒执行用户的请求。 具体的请求过程是:服务启动时,创建一个一维线程数组(maxThread=200个),并创建空闲线程(minSpareThreads=5个)随时等待用户请求。当有用户请求时,调用threadpool.runIt(ThreadPoolRunnable)方法,将一个需要执行的实例传给ThreadPool中。其中用户需要执行的实例必须实现ThreadPoolRunnable接口。ThreadPool 首先查找空闲的线程,如果有则用它运行要执行ThreadPoolRunnable;如果没有空闲线程并且没有超过maxThreads,就一次性创建minSpareThreads个空闲线程;如果已经超过了maxThreads了,就等待空闲线程了。总之,要找到空闲的线程,以便用它执行实例。找到后,将该线程从线程数组中移走。接着唤醒已经找到的空闲线程,用它运行执行实例(ThreadPoolRunnable)。运行完ThreadPoolRunnable后,就将该线程重新放到线程数组中,作为空闲线程供后续使用。 由此可以看出,Tomcat的线程池实现是比较简单的,ThreadPool.java也只有840行代码。用一个一维数组保存空闲的线程,每次以一个较小步伐(5个)创建空闲线程并放到线程池中。使用时从数组中移走空闲的线程,用完后,再“归还”给线程池。ThreadPool提供的仅仅是线程池的实现,而如何使用线程池也是有很大学问的。让我们看看Tomcat是如何使用ThreadPool的吧。 Tomcat有两种EndPoint,分别是AprEndpoint和PoolTcpEndpoint。前者自己实现了一套线

11线程池的使用

第11章线程池的使用 第8章讲述了如何使用让线程保持用户方式的机制来实现线程同步的方法。用户方式的同步机制的出色之处在于它的同步速度很快。如果关心线程的运行速度,那么应该了解一下用户方式的同步机制是否适用。 到目前为止,已经知道创建多线程应用程序是非常困难的。需要会面临两个大问题。一个是要对线程的创建和撤消进行管理,另一个是要对线程对资源的访问实施同步。为了对资源访问实施同步,Wi n d o w s提供了许多基本要素来帮助进行操作,如事件、信标、互斥对象和关键代码段等。这些基本要素的使用都非常方便。为了使操作变得更加方便,唯一的方法是让系统能够自动保护共享资源。不幸的是,在Wi n d o w s提供一种让人满意的保护方法之前,我们已经有了一种这样的方法。 在如何对线程的创建和撤消进行管理的问题上,人人都有自己的好主意。近年来,我自己创建了若干不同的线程池实现代码,每个实现代码都进行了很好的调整,以便适应特定环境的需要。M i c r o s o f t公司的Windows 2000提供了一些新的线程池函数,使得线程的创建、撤消和基本管理变得更加容易。这个新的通用线程池并不完全适合每一种环境,但是它常常可以适合你的需要,并且能够节省大量的程序开发时间。 新的线程池函数使你能够执行下列操作: ? 异步调用函数。 ? 按照规定的时间间隔调用函数。 ? 当单个内核对象变为已通知状态时调用函数。 ? 当异步I / O请求完成时调用函数。 为了完成这些操作,线程池由4个独立的部分组成。表11 - 1显示了这些组件并描述了控制其行为特性的规则。 表11-1 线程池的组件及其行为特性

多线程编程的详细说明完整版

VB .NET多线程编程的详细说明 作者:陶刚整理:https://www.doczj.com/doc/2d14783420.html, 更新时间:2011-4-1 介绍 传统的Visual Basic开发人员已经建立了同步应用程序,在这些程序中事务按顺序执行。尽管由于多个事务多多少少地同时运行使多线程应用程序效率更高,但是使用先前版本的Visual Basic很难建立这类程序。 多线程程序是可行的,因为操作系统是多任务的,它有模拟同一时刻运行多个应用程序的能力。尽管多数个人计算机只有一个处理器,但是现在的操作系统还是通过在多个执行代码片断之间划分处理器时间提供了多任务。线程可能是整个应用程序,但通常是应用程序可以单独运行的一个部分。操作系统根据线程的优先级和离最近运行的时间长短给每一个线程分配处理时间。多线程对于时间密集型事务(例如文件输入输出)应用程序的性能有很大的提高。 但是也有必须细心的地方。尽管多线程能提高性能,但是每个线程还是需要用附加的内存来建立和处理器时间来运行,建立太多的线程可能降低应用程序的性能。当设计多线程应用程序时,应该比较性能与开销。 多任务成为操作系统的一部分已经很久了。但是直到最近Visual Basic程序员才能使用无文档记录特性(undocumented)或者间接使用COM组件或者操作系统的异步部分执行多线程事务。.NET框架组件为开发多线程应用程序,在System.Threading名字空间中提供了全面的支持。 本文讨论多线程的好处以及怎样使用Visual Basic .NET开发多线程应用程序。尽管Visual Basic .NET和.NET框架组件使开发多线程应用程序更容易,但是本文作了调整使其适合高级读者和希望从早期Visual Basic转移到Visual Basic .NET的开发人员。 多线程处理的优点 尽管同步应用程序易于开发,但是它们的性能通常比多线程应用程序低,因为一个新的事务必须等待前面的事务完成后才能开始。如果完成某个同步事务的时间比预想的要长,应用程序可能没有响应。多线程处理可以同时运行多个过程。例如,字处理程序能够在继续操作文档的同时执行拼写检查事务。因为多线程应用程序把程序分解为独立的事务,它们能通过下面的途径充分提高性能: l 多线程技术可以使程序更容易响应,因为在其它工作继续时用户界面可以保持激活。 l 当前不忙的事务可以把处理器时间让给其它事务。 l 花费大量处理时间的事务可以周期性的把时间让给其它的事务。 l 事务可以在任何时候停止。 l 可以通过把单独事务的优先级调高或调低来优化性能。 明确地建立多线程应用程序的决定依赖于几个因素。多线程最适合下面的情况:

手把手教你做一个java线程池小例子

废话不多说开整 我用的是eclipse(这应该没多大影响) 建一个工程java工程和web工程都行然后建一个包建一个类带main方法 首先贴出来的是内部类 //继承了runnable接口 class MyTask implements Runnable { private int taskNum; public MyTask(int num) { this.taskNum = num; } @Override public void run() { System.out.println("正在执行task "+taskNum); try { //写业务 Thread.currentThread().sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("task "+taskNum+"执行完毕!"); } } 接下来就是这个类 public class testOne { public static void main(String[] args) { ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 7, 10, https://www.doczj.com/doc/2d14783420.html,LISECONDS, new ArrayBlockingQueue(2),new ThreadPoolExecutor.DiscardOldestPolicy() );

for(int i=0;i<15;i++){ MyTask myTask = new MyTask(i); executor.execute(myTask); System.out.println("线程池中线程数目: "+executor.getPoolSize()+"队列等待执行的任务数目:"+ executor.getQueue().size()+"已经执行完别的任务数目: "+executor.getCompletedTaskCount()); } executor.shutdown(); } } 接下来在说明一下ThreadPoolExecutor的参数设置ThreadPoolExecutor(int corePoolSize,//线程池维护线程的最少数量 int maximumPoolSize,//线程池维护线程的最大数量 long keepAliveTime,//线程池维护线程所允许的空闲时间 TimeUnit unit, 线程池维护线程所允许的空闲时间单位 BlockingQueue workQueue,线程池所使用的缓存队列 RejectedExecutionHandler handler线程池对拒绝任务的处理策略 ) handler有四个选择: ThreadPoolExecutor.AbortPolicy() 抛出java.util.concurrent.RejectedExecutionException异常 ThreadPoolExecutor.CallerRunsPolicy() 重试添加当前的任务,他会自动重复调用execute()方法 ThreadPoolExecutor.DiscardOldestPolicy() 抛弃旧的任务 ThreadPoolExecutor.DiscardPolicy() 抛弃当前的任务 上面是一个例子接下来再来一个例子

JAVA服务器端Socket线程池

JAVA服务器端Socket线程池 import java.util.Vector; import https://www.doczj.com/doc/2d14783420.html,.*; import java.io.*; public class ThreadPool { public static final int MAX_THREADS = 100; public static final int MAX_SPARE_THREADS = 50; public static final int MIN_SPARE_THREADS = 10; public static final int WORK_WAIT_TIMEOUT = 60 * 1000; protected Vector pool; //存放空闲线程 protected MonitorRunnable monitor; //A monitor thread that monitors the pool for idel thre ads. protected int maxThreads; //Max number of threads that you can open in the pool. protected int minSpareThreads; //Min number of idel threads that you can leave in the po ol. protected int maxSpareThreads; //Max number of idel threads that you can leave in the p ool. protected int currentThreadCount; //Number of threads in the pool. protected int currentThreadsBusy; //Number of busy threads in the pool. protected boolean stopThePool; //Flag that the pool should terminate all the threads and stop. /** * Construct */ public ThreadPool() { maxThreads = MAX_THREADS; maxSpareThreads = MAX_SPARE_THREADS; minSpareThreads = MIN_SPARE_THREADS; currentThreadCount = 0; currentThreadsBusy = 0; stopThePool = false; } /** * 启动线程池 */ public synchronized void start() { adjustLimits(); //调整最大和最小线程数及最大和最小多余线程数. openThreads(minSpareThreads); //打开初始线程

线程池原理 C++实现

线程池原理及创建(C++实现) 时间:2010‐02‐25 14:40:43来源:网络 作者:未知 点击:2963次 本文给出了一个通用的线程池框架,该框架将与线程执行相关的任务进行了高层次的抽象,使之与具体的执行任务无关。另外该线程池具有动态伸缩性,它能根据执行任务的轻重自动调整线程池中线程的数量。文章的最后,我们给出一个 本文给出了一个通用的线程池框架,该框架将与线程执行相关的任务进行了高层次的抽象,使之与具体的执行任务无关。另外该线程池具有动态伸缩性,它能根据执行任务的轻重自动调整线程池中线程的数量。文章的最后,我们给出一个简单示例程序,通过该示例程序,我们会发现,通过该线程池框架执行多线程任务是多么的简单。 为什么需要线程池 目前的大多数网络服务器,包括Web服务器、Email服务器以及数据库服务器等都具有一个共同点,就是单位时间内必须处理数目巨大的连接请求,但处理时间却相对较短。 传统多线程方案中我们采用的服务器模型则是一旦接受到请求之后,即创建一个新的线程,由该线程执行任务。任务执行完毕后,线程退出,这就是是“即时创建,即时销毁”的策略。尽管与创建进程相比,创建线程的时间已经大大的缩短,但是如果提交给线程的任务是执行时间较短,而且执行次数极其频繁,那么服务器将处于不停的创建线程,销毁线程的状态。 我们将传统方案中的线程执行过程分为三个过程:T1、T2、T3。 T1:线程创建时间 T2:线程执行时间,包括线程的同步等时间 T3:线程销毁时间

那么我们可以看出,线程本身的开销所占的比例为(T1+T3) / (T1+T2+T3)。如果线程执行的时间很短的话,这比开销可能占到20%‐50%左右。如果任务执行时间很频繁的话,这笔开销将是不可忽略的。 除此之外,线程池能够减少创建的线程个数。通常线程池所允许的并发线程是有上界的,如果同时需要并发的线程数超过上界,那么一部分线程将会等待。而传统方案中,如果同时请求数目为2000,那么最坏情况下,系统可能需要产生2000个线程。尽管这不是一个很大的数目,但是也有部分机器可能达不到这种要求。 因此线程池的出现正是着眼于减少线程池本身带来的开销。线程池采用预创建的技术,在应用程序启动之后,将立即创建一定数量的线程(N1),放入空闲队列中。这些线程都是处于阻塞(Suspended)状态,不消耗CPU,但占用较小的内存空间。当任务到来后,缓冲池选择一个空闲线程,把任务传入此线程中运行。当N1个线程都在处理任务后,缓冲池自动创建一定数量的新线程,用于处理更多的任务。在任务执行完毕后线程也不退出,而是继续保持在池中等待下一次的任务。当系统比较空闲时,大部分线程都一直处于暂停状态,线程池自动销毁一部分线程,回收系统资源。 基于这种预创建技术,线程池将线程创建和销毁本身所带来的开销分摊到了各个具体的任务上,执行次数越多,每个任务所分担到的线程本身开销则越小,不过我们另外可能需要考虑进去线程之间同步所带来的开销。 构建线程池框架 一般线程池都必须具备下面几个组成部分: 线程池管理器:用于创建并管理线程池 工作线程: 线程池中实际执行的线程

tcl多线程编程的使用说明

321C H A P T E R II. Advanced Tcl 21Multi-Threaded Tcl Scripts This chapter describes the Thread extension for creating multi-threaded Tcl scripts. This Chapter is from Practical Programming in Tcl and Tk, 4th Ed. Copyright 2003 ? Brent Welch, Ken Jones https://www.doczj.com/doc/2d14783420.html,/book/ T hread support, a key feature of many languages, is a recent addition to Tcl. That’s because the Tcl event loop supports features implemented by threads in most other languages, such as graphical user interface management, multi-client servers, asynchronous communication,and scheduling and timing operations. However, although Tcl’s event loop can replace the need for threads in many circumstances, there are still some instances where threads can be a better solution: ?Long-running calculations or other processing, which can “starve” the event loop ?Interaction with external libraries or processes that don’t support asynchro- nous communication ?Parallel processing that doesn’t adapt well to an event-driven model ?Embedding Tcl into an existing multi-threaded application What are Threads? Traditionally , processes have been limited in that they can do only one thing at a time. If your application needed to perform multiple tasks in parallel, you designed the application to create multiple processes. However, this approach has its drawbacks. One is that processes are relatively “heavy” in terms of the resources they consume and the time it takes to create them. For applications that frequently create new processes — for example, servers that create a new

相关主题
文本预览
相关文档 最新文档