Java多线程及线程池

原创 2007年10月02日 16:04:00
我的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,以及其他参考书籍。

相关文章推荐

java.util.concurrent 多线程框架---线程池编程(三)

1 引言 在软件项目开发中,许多后台服务程序的处理动作流程都具有一个相同点,就是:接受客户端发来的请求,对请求进行一些相关的处理,最后将处理结果返回给客户 端。这些请求的来源和方式可能会各不相同,但...
  • gm_163
  • gm_163
  • 2012年09月10日 10:26
  • 1160

Java多线程总结(6)— 线程池的基本使用和执行流程分析

1 线程池的实现原理及基本类结构  合理利用线程池能够带来三个好处。 降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。 提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立...
  • Mark_LQ
  • Mark_LQ
  • 2015年12月18日 21:36
  • 4924

多线程框架线程池编程

  • 2012年08月09日 17:11
  • 521KB
  • 下载

Java 多线程(七)——线程组与线程池

Java中使用ThreadGroup来表示线程组,它可以对一批线程进行分类管理。对线程组的控管理,即同时控制线程组里面的这一批线程。...
  • Zen99T
  • Zen99T
  • 2016年05月02日 15:17
  • 6899
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Java多线程及线程池
举报原因:
原因补充:

(最多只允许输入30个字)