programing

Java에서 스레드를 올바르게 중지하려면 어떻게 해야 합니다.

prostudy 2022. 7. 2. 12:08
반응형

Java에서 스레드를 올바르게 중지하려면 어떻게 해야 합니다.

자바에서 스레드를 올바르게 정지하기 위한 솔루션이 필요합니다.

있다IndexProcessorRunnable " " " run run run" :

public class IndexProcessor implements Runnable {

    private static final Logger LOGGER = LoggerFactory.getLogger(IndexProcessor.class);

    @Override
    public void run() {
        boolean run = true;
        while (run) {
            try {
                LOGGER.debug("Sleeping...");
                Thread.sleep((long) 15000);

                LOGGER.debug("Processing");
            } catch (InterruptedException e) {
                LOGGER.error("Exception", e);
                run = false;
            }
        }

    }
}

제가 있는 게 있어요.ServletContextListener"CHANGE: "CHANGE: "CHANGE: " 。

public class SearchEngineContextListener implements ServletContextListener {

    private static final Logger LOGGER = LoggerFactory.getLogger(SearchEngineContextListener.class);

    private Thread thread = null;

    @Override
    public void contextInitialized(ServletContextEvent event) {
        thread = new Thread(new IndexProcessor());
        LOGGER.debug("Starting thread: " + thread);
        thread.start();
        LOGGER.debug("Background process successfully started.");
    }

    @Override
    public void contextDestroyed(ServletContextEvent event) {
        LOGGER.debug("Stopping thread: " + thread);
        if (thread != null) {
            thread.interrupt();
            LOGGER.debug("Thread successfully stopped.");
        }
    }
}

단, Tomcat을 셧다운하면 IndexProcessor 클래스에서 예외가 발생합니다.

2012-06-09 17:04:50,671 [Thread-3] ERROR  IndexProcessor Exception
java.lang.InterruptedException: sleep interrupted
    at java.lang.Thread.sleep(Native Method)
    at lt.ccl.searchengine.processor.IndexProcessor.run(IndexProcessor.java:22)
    at java.lang.Thread.run(Unknown Source)

JDK 1.6을 사용하고 있습니다.질문은 다음과 같습니다.

어떻게 하면 스레드를 멈추고 예외를 던지지 않을 수 있을까요?

추신: 사용하고 싶지 않습니다..stop();권장되지 않기 때문에 메서드를 사용합니다.

「」를 사용합니다.Thread.interrupt()완벽하게 받아들일 수 있는 방법이라고 생각합니다.실제로 위에서 제시한 플래그보다 선호될 수 있습니다. 가능한(「」등)에입니다.Thread.sleep또는 java.nio 채널 운영 사용)을 통해 이러한 운영에서 즉시 벗어날 수 있습니다.

플래그를 사용할 경우 차단 작업이 완료될 때까지 기다려야 플래그를 확인할 수 있습니다.표준적인 것을 경우도 .InputStream/OutputStream방해할 수 없습니다.

이 경우 스레드가 중단되어도 입출력이 중단되지는 않지만 코드로 쉽게 실행할 수 있습니다(또한 안전하게 정지 및 청소할 수 있는 전략적 지점에서 이를 수행해야 합니다).

if (Thread.currentThread().isInterrupted()) {
  // cleanup and stop execution
  // for example a break in a loop
}

말씀드렸듯이 가장 큰 장점은Thread.interrupt()중단 가능한 콜에서 즉시 벗어날 수 있다는 것입니다.을 사용하다

서서 IndexProcessor합니다.run이치노

는 이 합니다.join()스레드 위에 올려놓고 끝날 때까지 기다립니다.

플래그가 스레드 세이프인지 확인하려면 휘발성 변수를 사용하거나 플래그로 사용되는 변수와 동기화된 getter 및 setter 메서드를 사용합니다.

public class IndexProcessor implements Runnable {

    private static final Logger LOGGER = LoggerFactory.getLogger(IndexProcessor.class);
    private volatile boolean running = true;

    public void terminate() {
        running = false;
    }

    @Override
    public void run() {
        while (running) {
            try {
                LOGGER.debug("Sleeping...");
                Thread.sleep((long) 15000);

                LOGGER.debug("Processing");
            } catch (InterruptedException e) {
                LOGGER.error("Exception", e);
                running = false;
            }
        }

    }
}

ㅇㅇㅇㅇ에서SearchEngineContextListener:

public class SearchEngineContextListener implements ServletContextListener {

    private static final Logger LOGGER = LoggerFactory.getLogger(SearchEngineContextListener.class);

    private Thread thread = null;
    private IndexProcessor runnable = null;

    @Override
    public void contextInitialized(ServletContextEvent event) {
        runnable = new IndexProcessor();
        thread = new Thread(runnable);
        LOGGER.debug("Starting thread: " + thread);
        thread.start();
        LOGGER.debug("Background process successfully started.");
    }

    @Override
    public void contextDestroyed(ServletContextEvent event) {
        LOGGER.debug("Stopping thread: " + thread);
        if (thread != null) {
            runnable.terminate();
            thread.join();
            LOGGER.debug("Thread successfully stopped.");
        }
    }
}

간단한 답변:스레드는 다음 두 가지 일반적인 방법 중 하나로 내부적으로 정지할 수 있습니다.

  • run 메서드는 리턴 서브루틴에 히트합니다.
  • 실행 메서드가 종료되고 암묵적으로 반환됩니다.

또한 외부에서 스레드를 중지할 수도 있습니다.

  • ★★system.exit 전체가 됩니다).
  • " " 를 합니다.interrupt()메서드 *
  • 합니다(예: 동작하는 것 같음).kill()또는stop())

*: 이것은 스레드를 정지시키는 것으로 기대됩니다.그러나 이 경우 스레드가 실제로 수행하는 작업은 전적으로 스레드 구현을 만들 때 개발자가 작성한 내용에 달려 있습니다.

실행 방식의 구현에서 흔히 볼 수 있는 패턴은while(boolean){}여기서 부울은 보통 이름이 붙은 것입니다.isRunning스레드 클래스의 멤버 변수이며 휘발성이 높으며 일반적으로 다른 스레드에서 setter 메서드(예: setter method)로 액세스할 수 있습니다.kill() { isRunnable=false; }이러한 서브루틴은 스레드가 종료하기 전에 보유하고 있는 리소스를 해방할 수 있도록 하기 때문에 좋습니다.

스레드는 항상 플래그를 체크하여 종료해야 합니다.run()루프(있는 경우)

스레드는 다음과 같습니다.

public class IndexProcessor implements Runnable {

    private static final Logger LOGGER = LoggerFactory.getLogger(IndexProcessor.class);
    private volatile boolean execute;

    @Override
    public void run() {
        this.execute = true;
        while (this.execute) {
            try {
                LOGGER.debug("Sleeping...");
                Thread.sleep((long) 15000);

                LOGGER.debug("Processing");
            } catch (InterruptedException e) {
                LOGGER.error("Exception", e);
                this.execute = false;
            }
        }
    }

    public void stopExecuting() {
        this.execute = false;
    }
}

그런 다음 콜을 통해 스레드를 종료할 수 있습니다.thread.stopExecuting()이렇게 하면 실이 깨끗하게 끝나지만 (수면 때문에) 최대 15초 걸립니다.스레드를 호출할 수 있습니다.interrupt()는 긴급한 경우에는 플래그를 항상 확인하는 것이 좋습니다.

15초 동안 기다리지 않으려면 다음과 같이 sleeve를 분할할 수 있습니다.

        ...
        try {
            LOGGER.debug("Sleeping...");
            for (int i = 0; (i < 150) && this.execute; i++) {
                Thread.sleep((long) 100);
            }

            LOGGER.debug("Processing");
        } catch (InterruptedException e) {
        ...

일반적으로 스레드는 중단되면 종료됩니다.그럼 네이티브 부울을 사용하면 어떨까요?isInterrupted()를 시도합니다.

Thread t = new Thread(new Runnable(){
        @Override
        public void run() {
            while(!Thread.currentThread().isInterrupted()){
                // do stuff         
            }   
        }});
    t.start();

    // Sleep a second, and then interrupt
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {}
    t.interrupt();

ref- 어떻게 실을 끊을 수 있나요? stop()을 사용하지 않음;

원하는 스레드 동기화용CountDownLatch프로세스가 완료될 때까지 스레드가 대기할 수 있습니다.이 경우 워커 클래스는 다음과 같이 설정됩니다.CountDownLatch츠키노의 콜await이 될 까지 차단합니다.는 0이 되기 때문입니다.countDown했습니다.하면 지정된 까지 기다릴 스레드를 할 수 있습니다.

public class IndexProcessor implements Runnable {

    private static final Logger LOGGER = LoggerFactory.getLogger(IndexProcessor.class);

    private final CountDownLatch countdownlatch;
    public IndexProcessor(CountDownLatch countdownlatch) {
        this.countdownlatch = countdownlatch;
    }


    public void run() {
        try {
            while (!countdownlatch.await(15000, TimeUnit.MILLISECONDS)) {
                LOGGER.debug("Processing...");
            }
        } catch (InterruptedException e) {
            LOGGER.error("Exception", e);
            run = false;
        }

    }
}

스레드의 을 countDown으로 합니다.CountDownLatch ★★★★★★★★★★★★★★★★★」join「 」의 「 」의 「 」

public class SearchEngineContextListener implements ServletContextListener {

    private static final Logger LOGGER = LoggerFactory.getLogger(SearchEngineContextListener.class);

    private Thread thread = null;
    private IndexProcessor runnable = null;
    private CountDownLatch countdownLatch = null;

    @Override
    public void contextInitialized(ServletContextEvent event) {
        countdownLatch = new CountDownLatch(1);
        Thread thread = new Thread(new IndexProcessor(countdownLatch));
        LOGGER.debug("Starting thread: " + thread);
        thread.start();
        LOGGER.debug("Background process successfully started.");
    }

    @Override
    public void contextDestroyed(ServletContextEvent event) {
        LOGGER.debug("Stopping thread: " + thread);
        if (countdownLatch != null) 
        {
            countdownLatch.countDown();
        } 
        if (thread != null) {
            try {
                thread.join();
            } catch (InterruptedException e) {
                LOGGER.error("Exception", e);
            }
            LOGGER.debug("Thread successfully stopped.");
        } 
    }
}

몇 가지 보충 정보입니다.Java 문서에는 플래그와 인터럽트가 모두 권장됩니다.

https://docs.oracle.com/javase/8/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html

private volatile Thread blinker;

public void stop() {
    blinker = null;
}

public void run() {
    Thread thisThread = Thread.currentThread();
    while (blinker == thisThread) {
        try {
            Thread.sleep(interval);
        } catch (InterruptedException e){
        }
        repaint();
    }
}

의 경우 ( )를 합니다.Thread.interrupt

public void stop() {
     Thread moribund = waiter;
      waiter = null;
      moribund.interrupt();
 }

Android에서 작업을 중단하지 않았기 때문에 이 방법을 사용하여 완벽하게 작동합니다.

boolean shouldCheckUpdates = true;

private void startupCheckForUpdatesEveryFewSeconds() {
    threadCheckChat = new Thread(new CheckUpdates());
    threadCheckChat.start();
}

private class CheckUpdates implements Runnable{
    public void run() {
        while (shouldCheckUpdates){
            System.out.println("Do your thing here");
        }
    }
}

 public void stop(){
        shouldCheckUpdates = false;
 }

언급URL : https://stackoverflow.com/questions/10961714/how-to-properly-stop-the-thread-in-java

반응형