【问题标题】:Setting a Java Thread's Runnable after construction构造后设置 Java 线程的 Runnable
【发布时间】:2013-05-31 15:19:48
【问题描述】:

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 并创建一个新线程,将 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();
    

这些已经足够好了,但我希望能够创建一个 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,它似乎可以按预期工作(它在通过 DDMS 验证的单独执行线程中执行我在 Runnable impl 的 run 方法中提供的任何代码)至少在 Android ICS 和 JB 上;上面给出的 FlexiThread 策略有什么错误/潜在危险/低效吗?如果是这样,在构造 Thread 子类的 Runnable 之后定义它的更好方法是什么?

【问题讨论】:

  • 为什么要扩展Thread?为什么不能直接扩展Runnable
  • 您的灵活方式与通常的旧方式之间的真正区别是什么?你需要在调用start()之前设置runnable。
  • AFAIK Android 仅支持 Java 6。

标签: java android multithreading


【解决方案1】:

我会使用 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();

【讨论】:

    【解决方案2】:

    上面给出的 FlexiThread 策略有什么错误/潜在危险/低效

    我会说不,这很好,尽管构建一个直到稍后才能启动的线程对我来说似乎很危险。当然,您应该添加一些好的代码 cmets 来解释发生了什么。如果 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();
    

    【讨论】:

    • Executors怎么样?
    • 是的,你是正确的@Fildor。彼得的答案是正确的。
    猜你喜欢
    • 1970-01-01
    • 2012-06-16
    • 1970-01-01
    • 1970-01-01
    • 2011-02-10
    • 1970-01-01
    • 2012-11-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多