Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/311.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么可以';Java线程对象不能重新启动吗?_Java_Multithreading - Fatal编程技术网

为什么可以';Java线程对象不能重新启动吗?

为什么可以';Java线程对象不能重新启动吗?,java,multithreading,Java,Multithreading,我知道不可能重新启动一个使用过的Java线程对象,但我找不到一个解释为什么不允许这样做;即使保证线程已经完成(参见下面的示例代码) 我不明白为什么start()(或者至少是restart())方法不能以某种方式将线程对象的内部状态(无论它们是什么)重置为新创建线程对象时的相同值 示例代码: class ThreadExample { public static void main(String[] args){ Thread myThread = new Thread(){

我知道不可能重新启动一个使用过的Java线程对象,但我找不到一个解释为什么不允许这样做;即使保证线程已经完成(参见下面的示例代码)

我不明白为什么
start()
(或者至少是
restart()
)方法不能以某种方式将线程对象的内部状态(无论它们是什么)重置为新创建线程对象时的相同值

示例代码:

class ThreadExample {

  public static void main(String[] args){

    Thread myThread = new Thread(){
      public void run() {
        for(int i=0; i<3; i++) {
          try{ sleep(100); }catch(InterruptedException ie){}
          System.out.print(i+", ");
        }
        System.out.println("done.");
      }
    };

    myThread.start();

    try{ Thread.sleep(500); }catch(InterruptedException ie){}
    System.out.println("Now myThread.run() should be done.");

    myThread.start(); // <-- causes java.lang.IllegalThreadStateException

  } // main

} // class
类线程示例{
公共静态void main(字符串[]args){
线程myThread=新线程(){
公开募捐{

对于(int i=0;i为什么不创建一个新线程?如果您担心创建MyThread对象的开销,请将其设置为可运行,并使用
新线程(MyThread)运行。start()因为他们不是那样设计的。从清晰的角度来看,这对我来说是有意义的。线程代表执行线程,而不是任务。当执行线程完成时,它完成了它的工作,如果它再次从顶部开始,它会把事情搞得一团糟


另一方面,Runnable表示一个任务,可以提交给多个线程,提交次数可以任意多。

我会提出另一个问题-为什么线程对象应该是可重启的

可以说,对一个只执行给定任务一次,然后永久完成的线程进行推理(可能实现)要容易得多。要重新启动线程,需要对程序在给定时间处于何种状态有一个更复杂的视图

因此,除非你能提出一个具体的理由,说明为什么重新启动一个给定的
线程
比仅仅创建一个具有相同
可运行
的新线程更好,否则我认为设计决策是为了更好


(这与关于可变变量vs
final
变量的争论大致相似——我发现最终“变量”更容易推理,更愿意创建多个新的常量变量,而不是重用现有变量。)

Java线程遵循基于以下状态图的生命周期。一旦线程处于最终状态,它就结束了。这就是设计。

我知道这是不可能的 重新启动已使用的Java线程对象,但 我找不到解释为什么会这样 是不允许的;即使是 保证线程具有 已完成(请参见下面的示例代码)

我的猜测是,线程可能直接绑定到实际的本机资源(出于效率或其他限制),这些资源可能在某些操作系统中重新启动,但在其他操作系统中不可重新启动。如果Java语言的设计者允许线程重新启动,他们可能会限制JVM可以运行的操作系统的数量

想想看,我想不出一个操作系统允许线程或进程在完成或终止后重新启动。当一个进程完成时,它就死了。你想要另一个,你就重新启动它。你永远不会重新启动它

除了底层操作系统带来的效率和限制问题外,还有分析和推理问题。当事物不可变或具有离散、有限的生命周期时,您可以对并发性进行推理。就像状态机一样,它们必须有一个终端状态。它是否已启动、等待、完成?诸如此类的事情不能如果你允许线程死灰复燃的话,这是不容易推理的

你还必须考虑线程复活的含义。重新创建它的堆栈,它的状态,是安全的复活吗?你能复活一个异常结束的线程吗?等等< /P>


太多毛,太复杂。所有这些都是为了微不足道的收益。最好将线程作为不可恢复的资源保留。

您可以通过使用
java.util.concurrent.ThreadPoolExecutor
,或者手动让线程调用
Runnable.run()
在给定的每个
可运行的
上,完成后不会实际退出

这并不完全是您要问的问题,但是如果您担心线程构造时间,那么它可以帮助解决该问题。下面是一些手动方法的示例代码:

public class ReusableThread extends Thread {
    private Queue<Runnable> runnables = new LinkedList<Runnable>();
    private boolean running;

    public void run() {
        running = true;
        while (running) {
            Runnable r;
            try {
                synchronized (runnables) {
                    while (runnables.isEmpty()) runnables.wait();
                    r = runnables.poll();
                }
            }
            catch (InterruptedException ie) {
                // Ignore it
            }

            if (r != null) {
                r.run();
            }
        }
    }

    public void stopProcessing() {
        running = false;
        synchronized (runnables) {
            runnables.notify();
        }
    }

    public void addTask(Runnable r) {
        synchronized (runnables) {
            runnables.add(r);
            runnables.notify();
        }
    }
}
公共类可重用线程扩展线程{
private Queue runnables=new LinkedList();
私有布尔运行;
公开募捐{
运行=真;
(跑步时){
可运行r;
试一试{
已同步(可运行){
while(runnables.isEmpty())runnables.wait();
r=runnables.poll();
}
}
捕获(中断异常ie){
//别理它
}
如果(r!=null){
r、 run();
}
}
}
公共无效停止处理(){
运行=错误;
已同步(可运行){
runnables.notify();
}
}
公共void addTask(可运行的r){
已同步(可运行){
添加(r);
runnables.notify();
}
}
}

显然,这只是一个例子。它需要更好的错误处理代码,也许还需要更多的调优可用。

如果您关心创建新线程对象的开销,那么您可以使用执行器

import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
public class Testes {
    public static void main(String[] args) {
        Executor executor = Executors.newSingleThreadExecutor();
        executor.execute(new Testes.A());
        executor.execute(new Testes.A());
        executor.execute(new Testes.A());
    }   
    public static class A implements Runnable{      
        public void run(){          
            System.out.println(Thread.currentThread().getId());
        }
    }
}

运行此程序时,您将看到所有可运行对象都使用了相同的线程。

我一直在搜索您似乎正在寻找的相同解决方案,我用这种方式解决了它。如果发生mousePressed事件,您可以终止它,也可以重用它,但它需要初始化,如下所示

class MouseHandler extends MouseAdapter{
    public void mousePressed(MouseEvent e) {            
        if(th.isAlive()){
            th.interrupt();
            th = new Thread();
        }
        else{
            th.start();
        }
    }

}

线程
不是线程。线程是代码的执行。
线程
是程序用于创建和管理线程生命周期的对象

假设你喜欢打网球,假设你和你