Java线程在不同对象之间处理

时间:2013-01-01 21:55:23

标签: java multithreading

当我尝试学习Java线程时,我通常在同一个类中遇到wait()notify()的代码示例(事实上几乎所有这些都是生产者 - 消费者示例)。在谷歌搜索各种例子后,遗憾的是我无法找到我需要的案例:

  • 管理器线程最初创建n个线程(并启动它们),其中http get请求在sigle线程中完成。
  • 对于单个工作线程,完成其生命需要大约20-30秒。
  • 在这里,我的经理线程必须知道哪些工作人员已经完成,并用新的线程替换完成的线程。

我想到了一种类似的方法(让n为5):

List<Runnable> runnables = new ArrayList<Runnable>();
for(int i = 0 ; i < 5 ; i++){
    runnables.add(new MyWorker(params));
}
for(Runnable myWorker : runnables){
   myWorker.run();
}

由于wait()不支持多个对象,所以我不能继续这样做。另一个解决方案是在管理器线程上实现忙等待,该线程为每个worker调用一些isFinished标志。但我不确定这是一个好方法(据我所知这是资源浪费)

2 个答案:

答案 0 :(得分:3)

在执行者框架的形式中,Java 6及更高版本中有一个现成的工具。

由于您希望拥有固定的线程池,因此最好使用:

ExecutorService service = Executors.newFixedThreadPool(5);

然后,您可以使用Runnable方法(由.execute()界面定义)提交Executor个实例。一旦池中的线程可用,它们将被提交到工作队列并出列。

如果您的各个线程工作方法返回一个值(即它们实现Callable<Something>),那么您可以使用.submit()方法(由ExecutorService定义,也是一个扩展的接口Executor),它将返回Future<Something>,您将.get()计算出的值。

以各种方式终止线程池:.shutdown()是最基本的,并将同步等待仍然活动的线程终止(并阻止提交新作业)。

Javadocs:ExecutorsExecutorServiceThreadPoolExecutor

其他链接:a book you should buy for all things thread-related(不包括Java 7的ForkJoinPool)。

PS:多么幸运,sample chapter of the book above (PDF)涵盖任务执行;)

答案 1 :(得分:1)

您可以使用semaphorewait/notify方法来完成您要执行的操作。方法是:

  1. 使用一次允许的最大线程数初始化semaphore
  2. 等到queue中的任务可用。
  3. 获取semaphore
  4. 运行任务,完成后发布semaphore
  5. 将所有四个步骤永远放在循环中,您就可以使用任务执行器了。这仅用于学习目的,因为@fge表示已存在ThreadPoolExecuter,它可以为您做同样的事情并且更加优化。

    import java.util.LinkedList;
    import java.util.Queue;
    import java.util.concurrent.Semaphore;
    
    public class ThreadExecuter extends Thread {
    
        Queue<Runnable> tasks = new LinkedList<Runnable>();
        Semaphore s;
        Object bin = new Object();
    
        public ThreadExecuter(int n) {
            s = new Semaphore(n);
        }
    
        public void addTask(Runnable r) {
            synchronized (bin) {
                tasks.add(r);
                bin.notifyAll();
            }
        }
    
        public void run() {
            while (true) {
                try {
                    final Runnable r;
                    synchronized (bin) {
                        while (tasks.isEmpty())
                            bin.wait();
                        r = tasks.poll();
                    }
    
                    s.acquire();
                    new Thread() {
                        public void run() {
                            r.run();
                            s.release();
                        }
                    }.start();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
    
        }
    }
    

    主要方法如下:

    import java.util.Random;
    
    public class ThreadTest {
    
        /**
         * @param args
         */
        public static void main(String[] args) {
                /* to make maximum 10 threads each running 1 runnable */
            ThreadExecuter executer = new ThreadExecuter(10);
            executer.start();
    
            for(int i = 0; i < 5000; i++) {
                        /* add task in executer, this is non blocking */
                executer.addTask(new Runnable() {
                    @Override
                    public void run() {
                        System.out.println("Task Executed in " 
                                            + Thread.currentThread().getId());
                        try {
                            Thread.sleep(new Random().nextInt(8000));
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                });
            }
        }
    
    }