我的Java老师说过要想好好的弄java,有两个东西必须得好好研究一下:net和thread。
而实际程序中使用多线程时多使用线程池来处理,这是一种有效的方式。
首先我介绍一种自己手写程序控制线程池的方法。网上能够找到很多这种程序, 我介绍的是Jeff Heaton的例程。这个例程共四个程序,以下是两个最主要的:
Done.java
package html.util.thread;
/**
*
* This is a thread pool for Java, it is
* simple to use and gets the job done. This program and
* all supporting files are distributed under the Limited
* GNU Public License (LGPL, http://www.gnu.org).
*
* This is a very simple object that
* allows the TheadPool to determine when
* it is done. This object implements
* a simple lock that the ThreadPool class
* can wait on to determine completion.
* Done is defined as the ThreadPool having
* no more work to complete.
*
* Copyright 2001 by Jeff Heaton
*
* @author Jeff Heaton (http://www.jeffheaton.com)
* @version 1.0
*/
public class Done {
/**
* The number of Worker object
* threads that are currently working
* on something.
*/
private int _activeThreads = 0;
/**
* This boolean keeps track of if
* the very first thread has started
* or not. This prevents this object
* from falsely reporting that the ThreadPool
* is done, just because the first thread
* has not yet started.
*/
private boolean _started = false;
/**
* This method can be called to block
* the current thread until the ThreadPool
* is done.
*/
synchronized public void waitDone() {
try {
while (_activeThreads > 0) {
wait();
}
} catch (InterruptedException e) {
}
}
/**
* Called to wait for the first thread to
* start. Once this method returns the
* process has begun.
*/
synchronized public void waitBegin() {
try {
while (!_started) {
wait();
}
} catch (InterruptedException e) {
}
}
/**
* Called by a Worker object
* to indicate that it has begun
* working on a workload.
*/
synchronized public void workerBegin() {
_activeThreads++;
_started = true;
notify();
}
/**
* Called by a Worker object to
* indicate that it has completed a
* workload.
*/
synchronized public void workerEnd() {
_activeThreads--;
notify();
}
/**
* Called to reset this object to
* its initial state.
*/
synchronized public void reset() {
_activeThreads = 0;
}
}
ThreadPool.java
package html.util.thread;
import java.util.*;
/**
* Java Thread Pool
*
* This is a thread pool that for Java, it is
* simple to use and gets the job done. This program and
* all supporting files are distributed under the Limited
* GNU Public License (LGPL, http://www.gnu.org).
*
* This is the main class for the thread pool. You should
* create an instance of this class and assign tasks to it.
*
* For more information visit http://www.jeffheaton.com.
*
* @author Jeff Heaton (http://www.jeffheaton.com)
* @version 1.0
*/
public class ThreadPool {
/**
* The threads in the pool.
*/
protected Thread threads[] = null;
/**
* The backlog of assignments, which are waiting
* for the thread pool.
*/
Collection assignments = new ArrayList(3);
/**
* A Done object that is used to track when the
* thread pool is done, that is has no more work
* to perform.
*/
protected Done done = new Done();
/**
* The constructor.
*
* @param size How many threads in the thread pool.
*/
public ThreadPool(int size) {
threads = new WorkerThread[size];
for (int i = 0; i < threads.length; i++) {
threads[i] = new WorkerThread(this);
threads[i].start();
}
}
/**
* Add a task to the thread pool. Any class
* which implements the Runnable interface
* may be assienged. When this task runs, its
* run method will be called.
*
* @param r An object that implements the Runnable interface
*/
public synchronized void assign(Runnable r) {
done.workerBegin();
assignments.add(r);
notify();
}
/**
* Get a new work assignment.
*
* @return A new assignment
*/
public synchronized Runnable getAssignment() {
try {
while (!assignments.iterator().hasNext())
wait();
Runnable r = (Runnable) assignments.iterator().next();
assignments.remove(r);
return r;
} catch (InterruptedException e) {
done.workerEnd();
return null;
}
}
/**
* Called to block the current thread until
* the thread pool has no more work.
*/
public void complete() {
done.waitBegin();
done.waitDone();
}
protected void finalize() {
done.reset();
for (int i = 0; i < threads.length; i++) {
threads[i].interrupt();
done.workerBegin();
threads[i].destroy();
}
done.waitDone();
}
}
/**
* The worker threads that make up the thread pool.
*
* @author Jeff Heaton
* @version 1.0
*/
class WorkerThread extends Thread {
/**
* True if this thread is currently processing.
*/
public boolean busy;
/**
* The thread pool that this object belongs to.
*/
public ThreadPool owner;
/**
* The constructor.
*
* @param o the thread pool
*/
WorkerThread(ThreadPool o) {
owner = o;
}
/**
* Scan for and execute tasks.
*/
public void run() {
Runnable target = null;
do {
target = owner.getAssignment();
if (target != null) {
target.run();
owner.done.workerEnd();
}
} while (target != null);
}
}
然后是两个实际使用这个线程池的程序:
TestWorkerThread.java
package html.util.thread.test;
import html.util.thread.Done;
/**
* This class shows an example worker thread that can be used with the thread
* pool. It demonstrates the main points that should be included in any worker
* thread. Use this as a starting point for your own threads.
*
* @author Jeff Heaton (http://www.jeffheaton.com)
* @version 1.0
*/
public class TestWorkerThread implements Runnable {
static private int count = 0;
private int taskNumber;
protected Done done;
/**
*
* @param done
*/
TestWorkerThread() {
count++;
taskNumber = count;
}
public void run() {
for (int i = 0; i < 100; i += 2) {
System.out.println("Task number: " + taskNumber
+ ",percent complete = " + i);
try {
Thread.sleep((int) (Math.random() * 500));
} catch (InterruptedException e) {
}
}
}
}
主程序 TestThreadPool.java
package html.util.thread.test;
import html.util.thread.ThreadPool;
/**
* Main class used to test the thread pool.
*
* @author Jeff Heaton (http://www.jeffheaton.com)
* @version 1.0
*/
public class TestThreadPool {
/**
* Main entry point.
*
* @param args
* No arguments are used.
*/
public static void main(String args[]) {
ThreadPool pool = new ThreadPool(10);
for (int i = 1; i < 25; i++) {
pool.assign(new TestWorkerThread());
}
pool.complete();
System.out.println("All tasks are done.");
}
}
整个程序不难理解,按着调用顺序可以很容易的理出头绪。
注意这个主程序中的pool.complete()方法,它是使用Done的等待唤醒机制将整个程序进程停留在此处,等各个线程都执行完成之后,再打印一句提示信息“All tasks are done”。而我们平时使用多线程时都是这句话出来之后,各个线程才慢条斯理的去执行。
但是有一个问题就是使用这个程序时当它完成之后可以很好的退出(有点记不清了)。而我将实现具体操作的程序用一个更有意义的程序来替代之后,所有任务都完成之后就挂住了,不退出。我检测之后发现是每个线程都处于WAITING等状态,在ThreadPool中的getAssignment()的while循环处wait了。还要使用方法将每个线程stop或者destroy掉才行。
然后我介绍一种Java自带的对线程池的支持。将java.util.concurrent包导入到主程序中,将main中的方法替换成:
ThreadPoolExecutor tpe = new ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue);
for (int i = 1; i < 25; i++) {
tpe.execute(new TestWorkerThread());
}
也可以实现线程池。但是这种方法有先前说的那种提示信息出来之后任务才不紧不慢的执行的问题。
我自己做东西的时候偏向于使用前一种,便于控制,当然萝卜白菜各有所爱。
而关于JAva自带的线程池的信息详见它的DOC,以及其他参考书籍。
而实际程序中使用多线程时多使用线程池来处理,这是一种有效的方式。
首先我介绍一种自己手写程序控制线程池的方法。网上能够找到很多这种程序, 我介绍的是Jeff Heaton的例程。这个例程共四个程序,以下是两个最主要的:
Done.java
package html.util.thread;
/**
*
* This is a thread pool for Java, it is
* simple to use and gets the job done. This program and
* all supporting files are distributed under the Limited
* GNU Public License (LGPL, http://www.gnu.org).
*
* This is a very simple object that
* allows the TheadPool to determine when
* it is done. This object implements
* a simple lock that the ThreadPool class
* can wait on to determine completion.
* Done is defined as the ThreadPool having
* no more work to complete.
*
* Copyright 2001 by Jeff Heaton
*
* @author Jeff Heaton (http://www.jeffheaton.com)
* @version 1.0
*/
public class Done {
/**
* The number of Worker object
* threads that are currently working
* on something.
*/
private int _activeThreads = 0;
/**
* This boolean keeps track of if
* the very first thread has started
* or not. This prevents this object
* from falsely reporting that the ThreadPool
* is done, just because the first thread
* has not yet started.
*/
private boolean _started = false;
/**
* This method can be called to block
* the current thread until the ThreadPool
* is done.
*/
synchronized public void waitDone() {
try {
while (_activeThreads > 0) {
wait();
}
} catch (InterruptedException e) {
}
}
/**
* Called to wait for the first thread to
* start. Once this method returns the
* process has begun.
*/
synchronized public void waitBegin() {
try {
while (!_started) {
wait();
}
} catch (InterruptedException e) {
}
}
/**
* Called by a Worker object
* to indicate that it has begun
* working on a workload.
*/
synchronized public void workerBegin() {
_activeThreads++;
_started = true;
notify();
}
/**
* Called by a Worker object to
* indicate that it has completed a
* workload.
*/
synchronized public void workerEnd() {
_activeThreads--;
notify();
}
/**
* Called to reset this object to
* its initial state.
*/
synchronized public void reset() {
_activeThreads = 0;
}
}
ThreadPool.java
package html.util.thread;
import java.util.*;
/**
* Java Thread Pool
*
* This is a thread pool that for Java, it is
* simple to use and gets the job done. This program and
* all supporting files are distributed under the Limited
* GNU Public License (LGPL, http://www.gnu.org).
*
* This is the main class for the thread pool. You should
* create an instance of this class and assign tasks to it.
*
* For more information visit http://www.jeffheaton.com.
*
* @author Jeff Heaton (http://www.jeffheaton.com)
* @version 1.0
*/
public class ThreadPool {
/**
* The threads in the pool.
*/
protected Thread threads[] = null;
/**
* The backlog of assignments, which are waiting
* for the thread pool.
*/
Collection assignments = new ArrayList(3);
/**
* A Done object that is used to track when the
* thread pool is done, that is has no more work
* to perform.
*/
protected Done done = new Done();
/**
* The constructor.
*
* @param size How many threads in the thread pool.
*/
public ThreadPool(int size) {
threads = new WorkerThread[size];
for (int i = 0; i < threads.length; i++) {
threads[i] = new WorkerThread(this);
threads[i].start();
}
}
/**
* Add a task to the thread pool. Any class
* which implements the Runnable interface
* may be assienged. When this task runs, its
* run method will be called.
*
* @param r An object that implements the Runnable interface
*/
public synchronized void assign(Runnable r) {
done.workerBegin();
assignments.add(r);
notify();
}
/**
* Get a new work assignment.
*
* @return A new assignment
*/
public synchronized Runnable getAssignment() {
try {
while (!assignments.iterator().hasNext())
wait();
Runnable r = (Runnable) assignments.iterator().next();
assignments.remove(r);
return r;
} catch (InterruptedException e) {
done.workerEnd();
return null;
}
}
/**
* Called to block the current thread until
* the thread pool has no more work.
*/
public void complete() {
done.waitBegin();
done.waitDone();
}
protected void finalize() {
done.reset();
for (int i = 0; i < threads.length; i++) {
threads[i].interrupt();
done.workerBegin();
threads[i].destroy();
}
done.waitDone();
}
}
/**
* The worker threads that make up the thread pool.
*
* @author Jeff Heaton
* @version 1.0
*/
class WorkerThread extends Thread {
/**
* True if this thread is currently processing.
*/
public boolean busy;
/**
* The thread pool that this object belongs to.
*/
public ThreadPool owner;
/**
* The constructor.
*
* @param o the thread pool
*/
WorkerThread(ThreadPool o) {
owner = o;
}
/**
* Scan for and execute tasks.
*/
public void run() {
Runnable target = null;
do {
target = owner.getAssignment();
if (target != null) {
target.run();
owner.done.workerEnd();
}
} while (target != null);
}
}
然后是两个实际使用这个线程池的程序:
TestWorkerThread.java
package html.util.thread.test;
import html.util.thread.Done;
/**
* This class shows an example worker thread that can be used with the thread
* pool. It demonstrates the main points that should be included in any worker
* thread. Use this as a starting point for your own threads.
*
* @author Jeff Heaton (http://www.jeffheaton.com)
* @version 1.0
*/
public class TestWorkerThread implements Runnable {
static private int count = 0;
private int taskNumber;
protected Done done;
/**
*
* @param done
*/
TestWorkerThread() {
count++;
taskNumber = count;
}
public void run() {
for (int i = 0; i < 100; i += 2) {
System.out.println("Task number: " + taskNumber
+ ",percent complete = " + i);
try {
Thread.sleep((int) (Math.random() * 500));
} catch (InterruptedException e) {
}
}
}
}
主程序 TestThreadPool.java
package html.util.thread.test;
import html.util.thread.ThreadPool;
/**
* Main class used to test the thread pool.
*
* @author Jeff Heaton (http://www.jeffheaton.com)
* @version 1.0
*/
public class TestThreadPool {
/**
* Main entry point.
*
* @param args
* No arguments are used.
*/
public static void main(String args[]) {
ThreadPool pool = new ThreadPool(10);
for (int i = 1; i < 25; i++) {
pool.assign(new TestWorkerThread());
}
pool.complete();
System.out.println("All tasks are done.");
}
}
整个程序不难理解,按着调用顺序可以很容易的理出头绪。
注意这个主程序中的pool.complete()方法,它是使用Done的等待唤醒机制将整个程序进程停留在此处,等各个线程都执行完成之后,再打印一句提示信息“All tasks are done”。而我们平时使用多线程时都是这句话出来之后,各个线程才慢条斯理的去执行。
但是有一个问题就是使用这个程序时当它完成之后可以很好的退出(有点记不清了)。而我将实现具体操作的程序用一个更有意义的程序来替代之后,所有任务都完成之后就挂住了,不退出。我检测之后发现是每个线程都处于WAITING等状态,在ThreadPool中的getAssignment()的while循环处wait了。还要使用方法将每个线程stop或者destroy掉才行。
然后我介绍一种Java自带的对线程池的支持。将java.util.concurrent包导入到主程序中,将main中的方法替换成:
ThreadPoolExecutor tpe = new ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue);
for (int i = 1; i < 25; i++) {
tpe.execute(new TestWorkerThread());
}
也可以实现线程池。但是这种方法有先前说的那种提示信息出来之后任务才不紧不慢的执行的问题。
我自己做东西的时候偏向于使用前一种,便于控制,当然萝卜白菜各有所爱。
而关于JAva自带的线程池的信息详见它的DOC,以及其他参考书籍。