동일한 스레드에서 start 메서드를 두 번 호출하는 것이 합법적입니까?


90

다음 코드는 프로그램에서 두 번째로 메서드를 java.lang.IllegalThreadStateException: Thread already started호출 할 때 연결됩니다 .start()

updateUI.join();    

if (!updateUI.isAlive()) 
    updateUI.start();

이것은 일 두 번째 시간 updateUI.start()이라고합니다. 나는 그것을 여러 번 밟았고 스레드가 호출되고 updateUI.start().

호출 updateUI.run()은 오류를 피하지만 스레드가 UI 스레드 (SO의 다른 게시물에서 언급 한 호출 스레드)에서 실행되도록합니다. 이것은 내가 원하는 것이 아닙니다.

스레드 한 번만 시작할 수 있습니까 ? 그렇다면 스레드를 다시 실행하려면 어떻게해야합니까? 이 특정 스레드는 UI 스레드에서 수행 한 것보다 스레드에서 수행하지 않고 사용자가 비합리적으로 오래 기다릴 경우 백그라운드에서 계산을 수행합니다.


9
왜 그냥 javadoc을 읽지 않았습니까? 계약을 명확하게 설명합니다.
mP.

답변:


112

로부터 자바 API 사양 에 대한 Thread.start방법 :

스레드를 두 번 이상 시작하는 것은 결코 합법적이지 않습니다. 특히 스레드가 실행을 완료 한 후에는 다시 시작할 수 없습니다.

더욱이:

오류 :
IllegalThreadStateException-스레드가 이미 시작된 경우.

예, a Thread는 한 번만 시작할 수 있습니다.

그렇다면 스레드를 다시 실행하려면 어떻게해야합니까?

Thread두 번 이상 실행해야하는 경우의 새 인스턴스를 Thread만들고 호출 start해야합니다.


감사. IDE와 스레드에 대한 Java 자습서 (Google도 마찬가지)로 문서를 확인했습니다. 앞으로 API 사양을 확인하겠습니다. 그 중요한 ".. 한 번 이상 시작하는 것이 합법적이지 않습니다."는 다른 판독에 없습니다.

@coobird, 이전 스레드 개체 이름을 새 Thread ()에 할당하면 이전 스레드가 완료된 후 이전 스레드가 가비지 수집됩니까 (즉, 자동으로 재활용됩니까, 아니면 명시 적으로 수행되어야합니까)?
snapfractalpop

스레드가 더 이상 실행되지 않는 한 가비지 수집됩니다.
flygoing

1
이 답변은 약간 오래되었습니다. 최신 Java 프로그램이 작업을 두 번 이상 수행 해야하는 경우 Thread매번 새로 생성해서는 안됩니다 . 대신,이에 작업을 제출해야 스레드 풀 (예 java.util.concurrent.ThreadPoolExecutor)
솔로몬은 천천히

13

맞습니다. 문서에서 :

스레드를 두 번 이상 시작하는 것은 결코 합법적이지 않습니다. 특히 스레드가 실행을 완료 한 후에는 다시 시작할 수 없습니다.

반복 계산을 위해 무엇을 할 수 있는지에 관해서는 SwingUtilities invokeLater 메소드를 사용할 수있는 것처럼 보입니다 . 이미 run()직접 호출을 실험하고 있습니다. 즉 Runnable, raw가 아닌 ​​a 사용에 대해 이미 생각하고 Thread있습니다. 작업 invokeLater에만 방법을 사용 해보고 Runnable그것이 당신의 정신 패턴에 조금 더 잘 맞는지 확인하십시오.

다음은 문서의 예입니다.

 Runnable doHelloWorld = new Runnable() {
     public void run() {
         // Put your UI update computations in here.
         // BTW - remember to restrict Swing calls to the AWT Event thread.
         System.out.println("Hello World on " + Thread.currentThread());
     }
 };

 SwingUtilities.invokeLater(doHelloWorld);
 System.out.println("This might well be displayed before the other message.");

해당 println호출을 계산으로 대체하면 정확히 필요한 것일 수 있습니다.

편집 : 댓글에 대한 후속 조치로 원본 게시물에서 Android 태그를 발견하지 못했습니다. Android 작업에서 invokeLater에 해당하는 것은 Handler.post(Runnable). javadoc에서 :

/**
 * Causes the Runnable r to be added to the message queue.
 * The runnable will be run on the thread to which this handler is
 * attached.
 *
 * @param r The Runnable that will be executed.
 *
 * @return Returns true if the Runnable was successfully placed in to the
 *         message queue.  Returns false on failure, usually because the
 *         looper processing the message queue is exiting.
 */

따라서 Android 세계에서는 위와 동일한 예제를 사용하여 Swingutilities.invokeLaterHandler.


OP는 SwingUtilities를 포함하지 않는 Android의 스레딩에 대해 묻습니다.
Austyn Mahoney

@Austyn, 당신 말이 맞아요. 병렬 Android 코드를 설명하기 위해 Handler.post ()에 대한 설명을 추가했습니다.
Bob Cross

1
UI를 업데이트하려는 경우 또 다른 방법은 자체 Handler 를 사용 RunOnUIThread(Runnable)하거나 View.post(Runnable)만드는 것입니다. 이들은 UI를 업데이트 할 수 있도록 메인 스레드에서 실행 파일을 실행합니다.
Austyn Mahoney

3

방금 도착한 답변은 자신이하는 일을하지 말아야하는 이유를 다룹니다. 실제 문제를 해결하기위한 몇 가지 옵션이 있습니다.

이 특정 스레드는 UI 스레드에서 수행 한 것보다 스레드에서 수행하지 않고 사용자가 비합리적으로 오래 기다릴 경우 백그라운드에서 계산을 수행합니다.

자신의 스레드를 덤프하고 AsyncTask.

또는 필요할 때 새 스레드를 만듭니다.

또는 스레드를 LinkedBlockingQueue다시 시작하지 않고 작업 대기열 (예 :)에서 작동하도록 스레드를 설정합니다 .


3

아니요 , Thread를 다시 시작할 수 없습니다. 그렇게하면 runtimeException java.lang.IllegalThreadStateException이 발생합니다. >

그 이유는 일단 run () 메소드가 Thread에 의해 실행되면 죽은 상태가되기 때문입니다.

예를 들어 보겠습니다. 스레드를 다시 시작하고 그것에 start () 메서드를 호출하는 것 (내부적으로 run () 메서드를 호출 할 것임)을 호출하는 것은 죽은 사람에게 깨어나 실행하도록 요청하는 것과 같습니다. 그의 인생을 마친 후 사람은 죽은 상태로 이동합니다.

public class MyClass implements Runnable{

    @Override
    public void run() {
           System.out.println("in run() method, method completed.");
    }

    public static void main(String[] args) {
                  MyClass obj=new MyClass();            
        Thread thread1=new Thread(obj,"Thread-1");
        thread1.start();
        thread1.start(); //will throw java.lang.IllegalThreadStateException at runtime
    }

}

/ * run () 메소드의 OUTPUT, 메소드 완료. 스레드 "main"의 예외 java.lang.IllegalThreadStateException at java.lang.Thread.start (Unknown Source) * /

이것을 확인


2

해야 할 일은 Runnable을 만들고 Runnable을 실행할 때마다 새 Thread로 래핑하는 것입니다. 정말 추한 일이지만 다른 스레드로 스레드를 래핑하여 코드를 다시 실행할 수 있지만이 작업 만 수행하면됩니다.


어떤 스 니펫, 포장하는 방법?
Vinay

1

말했듯이 스레드는 두 번 이상 시작할 수 없습니다.

말의 입에서 바로 : Java API 사양

스레드를 두 번 이상 시작하는 것은 결코 합법적이지 않습니다. 특히 스레드가 실행을 완료 한 후에는 다시 시작할 수 없습니다.

스레드에서 진행중인 모든 작업을 다시 실행해야하는 경우 새 스레드를 만들고 실행해야합니다.


0

스레드를 재사용하는 것은 Java API에서 불법 행위입니다. 그러나 실행 가능한 구현으로 래핑하고 해당 인스턴스를 다시 실행할 수 있습니다.


0

예, 이미 실행중인 스레드를 시작할 수 없습니다. 스레드가 이미 시작된 경우 런타임에 IllegalThreadStateException이 발생합니다.

실제로 시작 스레드가 필요한 경우 : 옵션 1) 스레드를 두 번 이상 실행해야하는 경우 스레드의 새 인스턴스를 만들고 그에 대해 start를 호출해야합니다.


0

스레드는 한 번만 시작할 수 있습니까?

예. 정확히 한 번 시작할 수 있습니다.

만약 그렇다면 스레드를 다시 실행하려면 어떻게해야합니까?이 특정 스레드는 백그라운드에서 계산을 수행하고 있습니다. UI 스레드에서 수행 한 것보다 스레드에서 수행하지 않고 사용자가 불합리하게 오래 기다려.

Thread다시 실행하지 마십시오 . 대신 Runnable을 만들고 HandlerThread의 Handler 에 게시하십시오 . 여러 개체 를 제출할 수 있습니다 . 데이터를 UI 스레드로 다시 보내려면 메서드에서 UI 스레드 및 프로세스 에 대해 게시하십시오 .RunnableRunnable run()MessageHandlerhandleMessage

예제 코드는이 게시물을 참조하십시오.

Android : 스레드에서 토스트


0

좋은 습관인지는 모르겠지만 run () 메서드 내에서 run ()을 호출하면 오류가 발생하지 않고 실제로 내가 원하는 것을 정확히 수행합니다.

나는 그것이 다시 스레드를 시작하지 않는다는 것을 알고 있지만 아마도 이것은 당신에게 유용 할 것입니다.

public void run() {

    LifeCycleComponent lifeCycleComponent = new LifeCycleComponent();

    try {
        NetworkState firstState = lifeCycleComponent.getCurrentNetworkState();
        Thread.sleep(5000);
        if (firstState != lifeCycleComponent.getCurrentNetworkState()) {
            System.out.println("{There was a NetworkState change!}");
            run();
        } else {
            run();
        }
    } catch (SocketException | InterruptedException e) {
        e.printStackTrace();
    }
}

public static void main(String[] args) {
    Thread checkingNetworkStates = new Thread(new LifeCycleComponent());
    checkingNetworkStates.start();
}

그것이 조금이라도 도움이되기를 바랍니다.

건배


-1

정말 추한 일이지만 다른 스레드로 스레드를 래핑하여 코드를 다시 실행할 수 있지만이 작업 만 수행하면됩니다.

스레드를 만든 프로그래머에 의해 발생하는 리소스 누수를 수정해야했지만 start ()하는 대신 run () 메서드를 직접 호출했습니다. 그래서 그것이 어떤 부작용을 일으키는 지 정말로 알지 못한다면 그것을 피하십시오.


그러나 제안은 run()직접 호출하는 것이 아니라 Runnable을 Thread에 포함하고 아마도 start().
H2ONaCl

@ H2ONaCl 내가 인용 한 텍스트를 읽으면 제안은 스레드를 스레드로 감싸는 것입니다. 원래 제안을 편집하기 전에 읽지 않았을 수 있습니다.
토르 벤
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.