在构造之后设置Java Thread的Runnable

时间:2013-05-31 15:19:49

标签: java android multithreading

JDK 7 Java文档提出了以下两个用于创建Java线程的习惯用法:

  1. 扩展线程并覆盖run()

    class PrimeThread extends Thread {
     long minPrime;
     PrimeThread(long minPrime) {
         this.minPrime = minPrime;
     }
    
     public void run() {
         // compute primes larger than minPrime
          . . .
     }
    }
    
    ...
    
    //And to launch the custom Thread
    
    PrimeThread p = new PrimeThread(143);
    
    p.start();
    
  2. 实现Runnable并创建一个新的Thread,将Runnable impl传递给它的构造函数

    class PrimeRun implements Runnable {
     long minPrime;
     PrimeRun(long minPrime) {
         this.minPrime = minPrime;
     }
    
     public void run() {
         // compute primes larger than minPrime
          . . .
     }
    }
    
    ...
    
    //And to launch a new Thread with this Runnable's behavior
    
    PrimeRun p = new PrimeRun(143);
    
    new Thread(p).start();
    
  3. 这些已经足够了,但是我希望能够创建Thread的子类,然后在稍后的某个时间定义和设置其Runnable实现(例如,不仅仅是在Thread的构造函数中)。据我所知,Java的Thread类没有提供实现这一目标的方法,所以我想出了以下内容:

    public class FlexiThread extends Thread{
    
    
    //The Runnable impl to be executed
    private Runnable mvRunner;
    
    //Construct an empty subclass of Thread
    public FlexiThread(){
        super();
    
    }
    
    //Construct a subclass of Thread which provides 
    //its Runnable impl immediately
    public FlexiThread(Runnable r){
        super(r);
        mvRunner = r;
    
    }
    
    /**
     * 
     * @return -- the Runnable implementation whose 
     * run() method will be invoked when this thread
     * is started
     */
    public Runnable getRunnableToExecute(){
        return mvRunner;
    }
    /**
     * @param runner -- the Runnable implementation whose 
     * run() method will be invoked when this thread
     * is started
     */ 
    public void setRunnableToExecute(Runnable runner){
        mvRunner = runner;
    }
    
    
    @Override
    public void run(){
        mvRunner.run();
    }
    
    }
    

    我测试了FlexiThread,它似乎按预期工作(它执行我在Runnable impl的run方法中给出的任何代码,在通过DDMS验证的单独执行线程中),至少在Android ICS和JB上;上面给出的FlexiThread策略是否有任何错误/潜在危险/低效?如果是这样,在构造之后定义Thread子类的Runnable可能是更好的方法吗?

2 个答案:

答案 0 :(得分:8)

我会使用Executor,因为它是可重用和可控的。

ExecutorService es = Executors.newSingleThreadedPool();

// set a runnable later.
es.submit(new MyRunnable());

// give it another runnable when that finishes.
es.submit(new MyRunnable2());

// don't need it any more
es.shutdown();

答案 1 :(得分:2)

  

上面给出的FlexiThread策略是否存在任何错误/潜在危险/效率低下

我会说不,这很好,虽然构建一个直到以后都无法启动的线程对我来说似乎很危险。当然你应该添加一些好的代码注释来解释发生了什么。如果尚未设置mvRunner,当你尝试启动线程时,我还会添加一些带有好消息的抛出。

一个改进是扩展线程,而是创建一个FlexiRunnable

public class FlexiRunnable implements Runnable {
     private Runnable delegate;
     private volatile boolean running = false;
     public void run() {
         running = true;
         if (delegate != null) {
            delegate.run();
         }
     }
     public void setDelegate(Runnable delegate) {
         if (running) {
            throw new IllegateStateException("The thread is already running...");
         }
         this.delegate = delegate;
     }
}

...
FlexiRunnable flexi = new FlexiRunnable();
Thread thread = new Thread(flexi);
... 
flexi.setDelegate(...);
thread.start();