[JDK] Thread에서.stop에서 스레드로 취소

3847 단어 threadConcurrent
Thread.stop은 사용하지 않는 것을 추천합니다. 왜냐하면 자바doc에서 제시한 링크에 있습니다.대략적으로 stop은 Thread Death 이상(Error)을 던지고 이상을 던지는 방법은 자물쇠(release monitor)를 방출하며 다른 방법은 원래 잠긴 보호 대상에 접근하는데 이러한 대상은 일치하지 않는 상태(잠긴 보호는 없지만 여러 라인에 접근함)에 있어 예측할 수 없는 결과를 초래할 수 있다.관건은 이런 현상이 관찰되기 어렵고 원인도 찾기 어렵다는 것이다(한 현상에 따라 스톱이 야기한 문제라는 것을 발견하기 어렵다).잠복기가 길어 며칠 뒤에야 문제가 생길 수 있기 때문에 이른바'우발적 현상'이 단시간에 재현될 수 없다는 것을 관찰하기 어렵다.
그래서 일반적으로run방법을 고쳐서while로 싸서while안에서 하나(또는 약간)상태를 판단하고cancle방법으로 취소(또는 정지)라인을 쓰는 것을 권장합니다. 이cancle는 간단합니다. 상태를 바꾸면 됩니다.

    private volatile Thread blinker;

    public void stop() {
        blinker = null;
    }

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

단지 상태의 동기화에 주의해야 한다(volatile 또는 다른 동기화 방식을 사용한다)
그러나 자바 병렬 프로그래밍에서 대가들은 이러한 모델의 문제점을 발견했다.while의 동작이 막히면while는 오래 걸리거나 영원히 물러나지 않을 것이다.

public void run() {
    try {
        while(!canceled) {
            blockingQueue.put(produceLongTimeJob());
        }
    } catch (InterruptedException ex) {
        /*   */
    }
}

생산자 소비자 모델을 사용하면 생산자가 소비자보다 빠르고 작업 대기열이 포화되어 다시 대기열을 막는put방법을 사용하면 막힌다. 이때 소비자가 소비 임무가 없으면 전체 작업이 멈추지 않는다. 정지 방법을 사용해서canceled의 상태를 바꾸더라도.
해결 방법인 자바 병렬 프로그래밍에서도 사용 중단을 제시했다."중단은 통상적으로 취소를 실현하는 가장 현명한 선택이다."

public void run() {
    try {
        while(!Thread.currentThread().isInterrupted()) {
            blockingQueue.put(produceLongTimeJob());
        }
    } catch (InterruptedException ex) {
        /*   */
    }
}

이러한 쓰기 방식은 운영 중단 감지 속도를 높일 뿐, 운영 작업에 앞서 중단이 감지되면 종료할 수 있습니다.사실try,catch 검사가 중단되면 논리적으로 중단을 사용하여 종료할 수 있습니다.
concurrent 패키지에서 ThreadExecute의 작업 라인의run 방법은while 검사 상태를 사용합니다

public void run() {
    try {
        Runnable task = firstTask;
        firstTask = null;
        while (task != null || (task = getTask()) != null) {
            runTask(task);
            task = null;
        }
    } finally {
        workerDone(this);
    }
}

getTask 방법에는 인터럽트를 사용하여 라인 종료를 알리는 것이 포함됩니다

    Runnable getTask() {
        for (;;) {
            try {
                int state = runState;
                if (state > SHUTDOWN)
                    return null;
                Runnable r;
                if (state == SHUTDOWN)  // Help drain queue
                    r = workQueue.poll();
                else if (poolSize > corePoolSize || allowCoreThreadTimeOut)
                    r = workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS);
                else
                    r = workQueue.take();
                if (r != null)
                    return r;
                if (workerCanExit()) {
                    if (runState >= SHUTDOWN) // Wake up others
                        interruptIdleWorkers();
                    return null;
                }
                // Else retry
            } catch (InterruptedException ie) {
                // On interruption, re-check runState
            }
        }
    }

interruptIdleWorkers () 는 일하지 않은 작업 라인을 중단하고, 공사 라인이 중단된 것을 감지하면 종료합니다.
그래서 다중 루틴 프로그래밍에서 반드시 인터럽트를 처리해야 한다. 왜냐하면 이것은 매우 흔하고 루틴이 종료를 잘 처리하기 위해 인터럽트도 처리해야 한다. 원인은 위에서 말한 바와 같다.

좋은 웹페이지 즐겨찾기