有这样的一个需求:
1、需要一个线程池(Java 1.4);
2、加入的线程可以指定不同的执行时间;
3、当执行时间到且线程池没满,则立即执行该线程;
4、如果执行时间到但线程池已满,则像普通的线程池一样阻塞直到线程池中有可用的位置。
下面是写出来的代码,包含简单的测试。
import java.util.Date;
import java.util.Vector;
import java.util.Calendar;
/**
* 带定时执行功能的线程池。
* 注意:
* <ol>
* <li>没有超时的设置,不会强制结束其中的线程。</li>
* <li>即使线程池没满,也不能严格保证线程按照既定时间
* 执行,通常会延迟 0.01 秒左右。不过对大多数情况来说这
* 是可以接受的。</li>
* </ol>
*/
public class TimedThreadPool {
private int size;
// 线程列表。注意,只有正在执行的线程才会出现在这个列表中。
private Vector threads = new Vector();
private final Lock lock = new Lock();
/**
* 构造函数
*
* @param size 线程池大小。在执行过程中可以随时调整。
*/
public TimedThreadPool(int size) {
this.size = size;
}
/**
* 添加一个定时执行的线程
*
* @param thread 要执行的线程
* @param executeTime 要执行的时间
*/
public void add(Thread thread, Date executeTime) {
new PooledThread(executeTime, thread, this).start();
}
/**
* 添加一个 ExecutableThread 对象
*
* @param thread ExecutableThread 对象
*/
protected void addExecutable(PooledThread thread) {
threads.add(thread);
}
/**
* 删除一个 ExecutableThread 对象
*
* @param thread ExecutableThread 对象
*/
protected void remove(PooledThread thread) {
threads.remove(thread);
}
/**
* 判断线程池是否满了
*
* @return 如果正在运行的线程数等于或超过指定大小
*/
public boolean isFull() {
return threads.size() >= size;
}
/**
* 获取线程池大小
*
* @return 线程池大小
*/
public int getSize() {
return size;
}
/**
* 设置线程池大小。注意,缩小线程池不会马上结束正在执行的线程。
*
* @param size 新的线程池大小
*/
public void setSize(int size) {
this.size = size;
}
/**
* 获得当前正在运行的线程数量
*
* @return 当前正在运行的线程数量
*/
public int getRunningThreadNum() {
return threads.size();
}
/**
* 获得锁对象
*
* @return 锁对象
*/
public Lock getLock() {
return lock;
}
/**
* 测试
*
* @param args 命令行参数
*
* @throws Exception 如果出现错误
*/
public static void main(String[] args) throws Exception {
TimedThreadPool p = new TimedThreadPool(3);
for (int i = 0; i < 10; i++) {
TestThread tt = new TestThread(i + 1, p);
System.out.println("++ add thread " + (i + 1));
p.add(tt, later());
Thread.sleep(270);
}
}
// 测试方法:获得当前两秒后的时间
private static Date later() {
Calendar c = Calendar.getInstance();
c.add(Calendar.SECOND, 2);
return c.getTime();
}
}
/**
* 锁类
*/
class Lock {
}
/**
* 包装线程
*/
class PooledThread extends Thread {
private Date executeDate;
private Thread executable;
private TimedThreadPool pool;
/**
* 构造函数
*
* @param executeDate 执行时间
* @param executable 要执行的线程
* @param pool 线程池对象
*/
PooledThread(Date executeDate, Thread executable, TimedThreadPool pool) {
this.executeDate = executeDate;
this.executable = executable;
this.pool = pool;
}
public void run() {
Lock lock = pool.getLock();
boolean finished = false;
try {
while (!finished) {
boolean runnable = executeDate.before(new Date());
// 判断能否执行。如果能够执行则占个位子,然后释放锁对象
synchronized (lock) {
if (!pool.isFull() && runnable) {
pool.addExecutable(this);
} else if (pool.isFull()) {
// 如果执行时间到了但线程池是满的,则阻塞
lock.wait();
}
}
// 开始执行线程。线程的执行是异步的,所以这里不应该把持锁对象。
if (runnable) {
executable.run();
pool.remove(this);
finished = true;
// 启动阻塞的其他线程
synchronized (lock) {
lock.notify();
}
}
// 如果执行时间没到,那么到这里 finished 为 false。
// 问题是如果执行时间没到且线程池没满,那么这里将会是一个无限循环,CPU 占用 100%。
// 所以这里加上一点休息时间。
Thread.sleep(10);
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
pool.remove(this);
}
}
}
/**
* 测试线程
*/
class TestThread extends Thread {
protected int id;
private TimedThreadPool pool;
TestThread(int id, TimedThreadPool pool) {
this.id = id;
this.pool = pool;
}
public void run() {
try {
System.out.println(">>> thread " + id + " started, running threads: "
+ pool.getRunningThreadNum());
Thread.sleep(2000);
System.out.println("=== thread " + id + " finishing, running threads: "
+ pool.getRunningThreadNum());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
分享到:
相关推荐
计划线程池是指可以计划执行任务的线程池,例如在指定的时间执行任务。计划线程池可以使用 ScheduledThreadPoolExecutor 类来创建。 结论 JDK 自带线程池是 Java 语言中非常有用的工具,可以提高多线程编程的效率...
`get`方法会阻塞直到任务完成或者超过指定的超时时间,如果超时,则抛出`TimeoutException`。在超时后,我们可以调用`cancel`方法尝试取消任务,但要注意的是,只有当任务尚未开始执行或者正在执行的任务可以被中断...
"Android-AppExecutor应用线程池可以指定任务的优先级完全kotlin"这个主题主要涉及如何使用Kotlin构建一个定制的应用程序线程池,以便更好地控制任务执行的优先级和顺序。 首先,我们需要了解线程池的概念。线程池...
7. **Thread Pool Timers**: 通过`CreateThreadpoolTimer`和`SetThreadpoolTimer`,可以在指定时间间隔后执行回调函数。这种方式可以用于实现定时任务,而无需创建额外的线程。 8. **Thread Pool Environment**: ...
2. newFixedThreadPool(int nThreads):创建一个固定大小的线程池,池中维护着指定数量的工作线程,一旦工作线程因执行任务结束,将立即补充新的工作线程。 3. newCachedThreadPool():创建一个可缓存的线程池,...
3. **ScheduledThreadPoolExecutor**:支持定时任务执行的线程池,可以指定任务执行的延迟时间或周期。 #### 六、线程池的工作队列 在实现线程池时,通常会使用一个工作队列来存储等待执行的任务。这个队列可以是...
java实现的线程池,可以在指定时间间隔内有只有一个任务执行,同时也可以设定在线程执行结束后释放的时间。
1. newCachedThreadPool:创建一个可缓存线程池,线程空闲超过指定时间后会被回收,当线程池为空时,会新建线程来处理任务。 2. newSingleThreadExecutor:创建一个单线程线程池,所有任务都在一个线程中顺序执行,...
4. **线程超时策略**(Keep-Alive Time):如果线程池中超过核心线程数的线程空闲时间超过指定时间,这些线程将被终止。这有助于在无任务时降低资源消耗。 在提供的压缩包文件中,我们看到以下几个类: 1. **...
4. **空闲超时(Keep-Alive Time)**:当线程池中的线程数量超过核心线程数,且没有任务可执行时,空闲线程将在等待指定时间后被终止。 5. **拒绝策略(Rejected Execution Handler)**:当线程池和工作队列都满时...
通过构造函数或 `Change` 方法设置定时器的间隔时间和延迟时间,从而定期执行指定的任务。 #### 九、使用BackgroundWorker组件 对于Windows Forms或WPF等桌面应用程序而言,`System.ComponentModel....
`Thread.sleep()`方法让当前线程暂停执行指定时间,不释放锁,而`yield()`则让当前线程让出CPU执行权,但不释放锁,通常用于让相同或更高优先级的线程有机会执行。`join()`方法使得当前线程等待指定线程执行完毕后再...
- **`keepAliveTime`**:当线程池中的线程数目大于`corePoolSize`时,如果这时没有新的任务提交,核心线程外的空闲线程不会立即终止,而是会等待,直到等待了指定的时间量。 - **`unit`**:表示`keepAliveTime`参数...
3. **超时控制**:任务可以设置超时时间,超过指定时间未完成则会被取消。 4. **工作项优先级**:任务可以有优先级,高优先级的任务将优先被处理。 5. **工作线程的挂起和恢复**:在没有工作可做时,线程池可以挂...
4. **线程存活时间(Keep-Alive Time)**:当线程池中的线程数量超过核心线程数,并且没有任务需要执行时,超出核心线程的线程会在指定的存活时间内等待新任务,若超过这个时间仍无新任务,这些线程将被终止。...
在Java编程中,实现每天动态时间执行任务的功能通常涉及到事件监听和定时任务调度。这个项目“java监听器+quartz实现每天动态时间执行任务的功能”是结合了Java的监听器机制和Quartz定时任务框架来完成这样的需求。...
4. 如果当前线程池中的数量大于 `corePoolSize`,缓冲队列 `workQueue` 满,并且线程池中的数量等于 `maximumPoolSize`,那么通过 `handler` 所指定的策略来处理此任务。 三、线程池参数解释 * `corePoolSize`:这...
通过构造方法,可以指定线程池的以下关键参数: 1. **核心线程数**(Core Pool Size):线程池中保持的最小线程数。 2. **最大线程数**(Maximum Pool Size):线程池允许创建的最大线程数。 3. **空闲线程存活时间...
- **keepAliveTime**:当线程数超过基本大小时,多余的线程闲置时间达到指定时间后会被销毁。 - **unit**:keepAliveTime的时间单位。 - **workQueue**:用来存储等待执行的任务的阻塞队列。 - **threadFactory**:...
线程池的工作机制在于控制线程数量,它会将任务放入队列,然后根据线程池的设定创建并启动线程执行这些任务。如果线程数量超过最大限制,额外的任务会被排队等待,直到有线程完成任务释放资源。线程池的使用有三个...