ThreadPoolExecutor 线程池如何设置里面线程的最长执行时间?

syncml 2006-12-14 05:53:11
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.io.*;

public class ThreadTest {
private static int produceTaskSleepTime = 2;
public static void main(String[] args) {
//构造一个线程池
ThreadPoolExecutor producerPool = new ThreadPoolExecutor(2, 6, 4,
TimeUnit.SECONDS, new ArrayBlockingQueue(4),
new ThreadPoolExecutor.CallerRunsPolicy());

//每隔produceTaskSleepTime的时间向线程池派送一个任务。
int i=1;
while(true){
try {
Thread.sleep(produceTaskSleepTime);
String task = "task@ " + i;
System.out.println("put " + task);

producerPool.execute(new ThreadPoolTask(task));

i++;
if(i>100) break;
} catch (Exception e) {
e.printStackTrace();
}
}
}
}


class ThreadPoolTask implements Runnable,Serializable{

//JDK1.5中,每个实现Serializable接口的类都推荐声明这样的一个ID
private static final long serialVersionUID = 0;
private static int consumeTaskSleepTime = 200;
private Object threadPoolTaskData;

ThreadPoolTask(Object tasks){
this.threadPoolTaskData = tasks;
}

//每个任务的执行过程,现在是什么都没做,除了print和sleep,:)
public void run(){
System.out.println("start .."+threadPoolTaskData);
try {
//便于观察现象,等待一段时间
Thread.sleep(consumeTaskSleepTime);
} catch (Exception e) {
e.printStackTrace();
}
threadPoolTaskData = null;
}
}


ThreadPoolTask 如果因为某种原因一直停留在那里,这样导致线程池满了,而使后面的线程无法执行,基于这样的情况,如何能处理使那些占用很长时间的线程remove? 谢谢。急啊
...全文
1704 3 打赏 收藏 转发到动态 举报
写回复
用AI写文章
3 条回复
切换为时间正序
请发表友善的回复…
发表回复
虎叔 2006-12-15
  • 打赏
  • 举报
回复
Session mailSession = Session.getInstance(props, null);
Transport transport = mailSession.getTransport("smtp");
transport.connect((String) props.get("mail.smtp.host"), username,password);
transport.sendMessage(mimeMsg, mimeMsg.getAllRecipients());
System.out.println("发送邮件成功!");
==================
那可以不一定会打印“发送邮件成功!”,因为你前面的语句都有可能抛出异常。
试试把可能发生异常的语句放到try语句中,打印语句放在final中。
syncml 2006-12-14
  • 打赏
  • 举报
回复
ThreadPoolTask 就是调用javamail发送邮件

Session mailSession = Session.getInstance(props, null);
Transport transport = mailSession.getTransport("smtp");
transport.connect((String) props.get("mail.smtp.host"), username,password);
transport.sendMessage(mimeMsg, mimeMsg.getAllRecipients());
System.out.println("发送邮件成功!");

有些发送"发送邮件成功!"打不出来,则这个线程一直贮存在线程池里面了


核心部分
while (true) {

try {
lock.lock();
ob = (MMessage)queue.poll();
} finally {
lock.unlock();
}

try{
if(ob!=null){
serverThreadPool.execute(new ServiceThread(ob));
logger.debug("serverThreadPool.execute(new ServiceThread("+ob+"));");
}else{
Thread.sleep(produceTaskSleepTime);
}

}catch(Exception ex){
//e.printStackTrace();
logger.error("while thread",ex);
}
}


我在想会不会是Thread.sleep(produceTaskSleepTime);的问题
或者是
transport.connect((String) props.get("mail.smtp.host"), username,password);
transport.sendMessage(mimeMsg, mimeMsg.getAllRecipients());
的时候由于某些原因会一直不释放?
虎叔 2006-12-14
  • 打赏
  • 举报
回复
应该说你要去找原因为什么线程停留,是死锁就麻烦了。而不是把线程remove。
因为及时remove了,线程还是在内存中运行。当然你可以强制停止Thread.stop(),但是这样是不安全的,Java不建议作么做。
所以你还是要找出线程停留的BUG在那里。否则自己没有把握最好不要使用线程。
JAVA线程基本学习, JAVA多线程的特性= 线程: 本质上是一个对象池, 用来管理线程资源. 在任务执行前, 需要从线程中拿出线程执行. 在任务执行完成之后, 需要把线程放回线程. 线程好处: 降低资源的消耗, 线程本身是一种资源, 创建和销毁都会消耗CPU内存, 频繁的创建和销毁会浪内存. 提高任务执行的响应速度, 任务执行时, 可以不必等线程创建完成之后在执行,可以直接获取线程执行任务. 提高线程的可管理性, 线程不能无限制的创建, 需要进行统一的分配, 调优和监控. 不适用线程坏处: 频繁的线程创建和销毁会占用更多的CPU和内积. 频繁的创建和销毁会对gc产生比较大的压力. 线程太多,线程切换带来的开销将不可忽视. 线程太少, 多核CPU得不到充分利用, 浪费资源. 线程实现原理: 分为三部分: 核心线程 线程 队列 拒绝策略 主要流程: 1.判断核心线程是否已满, 如果不是, 则创建线程执行任务 2.如果核心线程满了, 判断队列是否满了, 如果队列没满, 将任务放在队列中 3.如果队列满了, 则判断线程是否已满, 如果没满, 创建线程执行任务 4.如果线程满了, 按照拒绝策略对任务进行处理 JDK中提供了一个线程工厂: Executors ,很多工厂方法, 可以创建多种线程 1.单一线程 ExecutorService newSingleThreadExecutor = Executors.newSingleThreadExecutor(); 该线程只有一个线程, 若多个任务被提交到此线程, 那么会被缓冲到队列,当线程空闲时,按照FIFO的方式进行处理. 2.固定数量线程 ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(5); 和创建单一线程类似, 不同的是线程中有多个线程, 可以并行处理任务, 若多个线程任务被提交到此线程, 会有以下执行过程: 如果线程的数量未达到指定数量, 则创建新线程执行任务. 如果线程的数量达到了指定数量, 而且此时有线程是空闲的, 则取出空闲线程执行任务. 如果没有线程是空闲的, 则将任务缓冲到队列, 当线程空闲的时候, 按照FIFO的方式进行处理. FIFO: 先进先出 3.带缓冲的线程线程中, 核心线程长度为0, 线程最大长度为Integer.MAX_VALUE.以SynchronousQueue作为等待队列, 从而每次往队列中插入一个元素, 必须等待另一个线程从这个队列删除一个元素. 定时调度 4.定时调度的线程 ExecutorService newCachedThreadPool = Executors.newScheduledThreadPool(); ScheduledExecutorService newScheduledThreadPool = Executors.newScheduledThreadPool(5); ExecutorService newWorkStealingPool = Executors.newWorkStealingPool() 线程家族 线程的顶层接口是Executor, 这个接口定义了一个核心方法executor(Runnable command), 这个方法最后被ThreadPoolExecutor类实现, 这个方法用来传入任务, 并且该类是线程的核心类, 构造方法如下 : public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue workQueue); public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue workQueue,ThreadFactory threadFactory); public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue workQueue,RejectedExecutionHandler handler); public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue workQueu, ThreadFactory threadFactory,RejectedExecutionHandler handler); 参数意义: CorePoolSize: 核心线程大小, 如果核心线程有空闲的位置, 新的任务就会被核心线程新建一个线程执行, 执行完毕不会销毁线程, 线程会进入缓冲队列等待再次被运行 MaximunPoolSize: 线程能创建最大的线程数量, 如果核心线程和缓冲队列都已经满了, 新的任务就会进来创建新的线程执行, 但是数量不能超过maximunPoolSize, 否则采取拒绝接受任务策略 KeepAliveTime: 非核心线程能够空闲的最长时间, 超过时间, 线程终止, 这个参数默认只有在线程数量超过核心线程大小时, 才会起作用. Unit: 时间单位, 和keepAliveTime配合使用. WorkQueue: 缓冲队列, 用来存放等待被执行的任务 ThreadFactory: 线程工厂, 用来创建线程, 一般有三个选择 ArrayBlockingQueue LinkedBlockingQueue SynchronousQueue Handler :拒绝处理策略, 线程数量大于最大线程数量就会拒绝处理策略, 四种策略为 ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。 ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。 ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程) ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务 Executor接口有一个子接口ExecutorService, ExecutorService的实现类AbstracExecutorService, 而ThreadPoolExecutor正是AbstracExecutorService的子类. ThreadPoolExecutor还有两个常用的方法shutdown和submit,两者都用来关闭线程, 但是submit有一个结果返回. 线程任务执行执行executor(Runnable command)方法后, 传入一个任务, public void execute(Runnable command) { if (command == null) throw new NullPointerException(); if (poolSize >= corePoolSize || !addIfUnderCorePoolSize(command)) { if (runState == RUNNING && workQueue.offer(command)) { if (runState != RUNNING || poolSize == 0) ensureQueuedTaskHandled(command); } else if (!addIfUnderMaximumPoolSize(command)) reject(command); } } (传入的对象实现了Runnable接口, 这就解释了: 为什么实现多线程的方式中继承Thread类不能使用线程了) 执行过程: 首先判断任务是否为空, 为空抛出空指针异常, 否则执行下一个判断: 当前线程数量是否小于核心线程线程数量, 是,则执行addIfUbderCorePollSize(command)方法, 在核心线程中创建新的线程, 并且执行这个任务 总结: 如果当前线程中的数目小于corePollSize, 则每来一个任务, 就会创建一个新的线程执行这个任务 如果当前线程中的线程数目>=corePollSize, 则每来一个任务, 会尝试将其添加到缓冲队列中, 如果添加成功, 则该任务会等待空闲线程将其取出去执行, 如果添加失败(一般是以为任务队列已经满了), 则会尝试创建新的线程执行这个任务. 如果当前线程中的线程数目达到maximunPoolSize, 则会采取任务拒绝策略进行处理. 如果线程中的线程数量大于corePoolSize时, 如果某线程空闲时间超过keepAliveTime, 线程将被终止, 直至线程中的线程数目小于等于corePoolSize; 如果允许核心池中的线程设置存活时间, 那么核心池中的线程空闲时间超过keepAliveTime, 线程也会被终止.

62,615

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧