重新启动java线程

时间:2014-12-05 10:19:22

标签: java multithreading executorservice

我想知道为什么ExecutorService实际上可以多次执行相同的Thread。 因为线程的通常生命周期终止于TERMINATED afaik ..

所以,

public class TestThread extends Thread {

  AtomicInteger counter = new AtomicInteger(0);
  @Override
  public void run() {
    System.out.printf("%d\n", counter.addAndGet(1));
  }

  public static void main(String[] args) throws InterruptedException {
    ExecutorService es = Executors.newCachedThreadPool();
    TestThread t = new TestThread();

    es.execute(t);
    es.execute(t);

    es.shutdown();
  }
}

这适用于我实际上会期望非法状态异常,例如:

t.start();
t.start(); =>BAM!

非常感谢解开执行背后的魔力!

4 个答案:

答案 0 :(得分:5)

ExecutorService.execute(Runnable)用新的Thread实例包装它们。如果您还打印线程ID,

@Override
public void run() {
    System.out.printf("%d %d%n", counter.addAndGet(1),
        Thread.currentThread().getId());
}

您将看到两个不同的线程正在运行。例如,

1 10
2 11

答案 1 :(得分:2)

Thread对象的start()方法不会被调用两次,甚至不会被调用一次:只使用对象的Runnable接口。每个Thread都会创建实际execute(),每个run()都会委托您的{{1}}方法。

答案 2 :(得分:2)

ExecutorService不会重新启动Thread。线程永远不能重新启动。

ExecutorService是一个线程 pool 。它管理一组长时间运行的线程,每个线程都能执行许多任务。

当你的代码为某些ExeuctorService,es和一些Runnable调用es.submit(r)时,r; submit函数将runnable添加到阻塞队列。

ExecutorService管理的每个线程都有一个run()方法,如下所示:

public void run() {
    while (true) {
        Runnable task = queue.take();
        task.run();
    }
}

当然,由于例外和shutdown()机制,它比那更复杂,但这是基本的想法。池线程基本上永远运行,等待任务执行。

答案 3 :(得分:1)

您无法重新启动线程,但您可以检测多次使用的线程;)

测试代码:

package com.stackoverflow.test;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;

public class TestOfCachedThreadPool {
  private static final int AMOUNT = 1000000;

  private static final class TestThread implements Runnable {
    private Map<Long, Long> mapOfUsage;

    private TestThread(Map<Long, Long> mapOfUsage) {
      this.mapOfUsage = mapOfUsage;
    }

    @Override
    public void run() {
      synchronized (mapOfUsage) {
        Long numberOfThreads=mapOfUsage.get(Thread.currentThread().getId());
        if(numberOfThreads==null){
          mapOfUsage.put(Thread.currentThread().getId(), 1l);
        }else{
          mapOfUsage.put(Thread.currentThread().getId(), ++numberOfThreads);
        }
      }

    }
  }

  public static void main(String[] args) {
    ThreadFactory threadFactory = Executors.defaultThreadFactory();
    final Map<Long, Long> mapOfUsage = new HashMap<>(AMOUNT * 2);
    ExecutorService service = Executors.newCachedThreadPool();
    for(int i=0;i<AMOUNT;i++){
      service.execute(threadFactory.newThread(new TestThread(mapOfUsage)));
    }
    for(Map.Entry<Long, Long> entry: mapOfUsage.entrySet()){
      if(entry.getValue()>1){
        System.out.println("Thread with id "+entry.getKey() +" was used "+entry.getValue()+ " times");
      }
    }
  }
}

输出:

  

ID为9的线程使用27198次

     

ID为11的线程使用了1810次

     

ID为13的线程使用了1294次

     

ID为15的线程使用3347次

     

ID为17的线程使用6709次

     

ID为19的线程使用7259次

     

ID为21的线程使用39335次

     

ID为23的线程使用了13552次

     

ID为25的线程使用535次

     

ID为27的线程使用19533次

     

ID为29的线程使用113495次

     

ID为31的线程使用62713次

     

ID为35的线程使用94103次

     

ID为33的线程使用了53641次

     

ID为5328的线程使用18922次

     

ID为16388的线程使用28501次

     

ID为16384的线程使用了114677次

     

ID为16386的线程使用了39次

     

ID为16698的线程使用60450次

     

ID为123096的线程使用了19944次

     

ID为123102的线程使用了60961次

     

ID为123115的线程使用24246次

     

ID为275492的线程使用了108399次

     

ID为275490的主题使用11973次

     

ID为380143的线程使用10433次

     

ID为363358的线程使用55989次

     

ID为692626的线程使用了6016次

     

ID为909079的主题使用了25782次

     

ID为965801的线程使用了32次

     

ID为948919的线程使用了1782次

     

ID为948872的线程使用了4次

     

ID为938802的线程被使用了24次

     

ID为923558的线程使用7302次