Как остановить потоки в Java

Я пишу программу, которая генерирует случайное число от 1 до 1000. Затем он использует пул из трех потоков для поиска в определенных диапазонах чисел в более широком диапазоне от 1 до 1000. Потоки проверяют каждое число в своем диапазоне и сравнивают его со случайным целевым числом, если оно совпадает, об этом говорится в сообщении на консоль. Если номер не совпадает, это также отражается в сообщении на консоль. Я пытаюсь выяснить, как завершить программу после достижения целевого числа и не продолжать анализ чисел, даже если цель уже найдена. Спасибо.

Это класс FindIt:

/** fill in later */
public class FindIt extends Thread
{
    private int numToFind;
    private int numToStart;
    private int numToEnd;

    public FindIt( int nF, int nS, int nE )
    {
        numToFind = nF;
        numToStart = nS;
        numToEnd = nE;
    }

    public void run()
    {
        int counter = 0;

        int numAt = numToStart;

        for ( int i = 0; i < ( numToEnd - numToStart ) + 1; i++ )
        {
            counter++;

            if ( counter == 10 )
            {
                counter = 0;
                Thread.yield();
            }

            if ( numAt++ == numToFind )
            {
                System.out.println( "The target number, " + numToFind + ", has been found by " + Thread.currentThread().getName() + "." );
            }

            else
            {
                System.out.println( Thread.currentThread().getName() + " has analyzed the number " + ( numAt - 1 ) + " - not the target number." );
            }

        }   
    }
}

Это программа с основным методом:

import java.util.Random; //imports Java's Random class
import java.util.concurrent.*;

/** fill in later */
public class NumberSearch
{
    public static void main( String [] args )
    {
        Random r = new Random(); //creates an instance of the Random class
        int randomNum = r.nextInt( 1001 ); //declares the integer randomNum and initilizes it to be a random interger in the range 0 inclusive to 1001 exclusive

        ExecutorService executor = Executors.newFixedThreadPool( 3 );

        FindIt find1 = new FindIt( randomNum, 0, 349);
        FindIt find2 = new FindIt( randomNum, 350, 699);
        FindIt find3 = new FindIt( randomNum, 700, 1000);

        executor.execute( find1 );
        executor.execute( find2 );
        executor.execute( find3 );

        executor.shutdown();
    }
}

person B. Freeman    schedule 29.04.2016    source источник
comment
Возможный дубликат Как правильно остановить поток в Java?   -  person Ravindra babu    schedule 29.04.2016
comment
@Ravindrababu: имейте в виду, что принятый ответ на этот вопрос не обрабатывает случай, когда задача выполняется в пуле потоков, весь подход с изменчивым флагом, созданным вручную, терпит неудачу при использовании Executors.   -  person Nathan Hughes    schedule 29.04.2016
comment
В порядке. Я отозвал свой голос.   -  person Ravindra babu    schedule 29.04.2016
comment
Связанный stackoverflow.com/questions/ 11915968/   -  person Tunaki    schedule 01.05.2016


Ответы (1)


Требуются две вещи:

  • Сделайте так, чтобы ваши задачи реагировали на прерывание, отметив Thread.currentThread().isInterrupted() и вернув задачу при обнаружении прерывания.

  • Используйте метод shutdownNow ExecutorService, чтобы прервать выполнение текущих задач. Метод выключения заставляет исполнителя перестать получать новые задачи, но позволяет задачам, уже переданным исполнителю, выполняться до завершения.

Не делайте для этого подкласс Thread, вы должны расширять Runnable или Callable, чтобы определять задачи, отправляемые исполнителю. Создание подкласса Thread означает, что задача выделяет поток ОС, который не нужен, поскольку фактические потоки уже созданы в пуле потоков. В этом примере, поскольку вы вычисляете число в своих задачах, может иметь смысл использовать Callable.

В java.util.concurrent есть класс, предназначенный для такого рода вещей. Пример отмены задач после того, как был найден ответ, приведен в Документация по API для ExecutorCompletionService.

FindIt изменен для обнаружения прерывания:

public class FindIt implements Runnable
{
    private int numToFind;
    private int numToStart;
    private int numToEnd;

    public FindIt( int nF, int nS, int nE )
    {
        numToFind = nF;
        numToStart = nS;
        numToEnd = nE;
    }

    public void run()
    {
        int counter = 0;

        int numAt = numToStart;

        for ( int i = 0; i < ( numToEnd - numToStart ) + 1; i++ )
        {
            if (Thread.currentThread().isInterrupted()) {
                System.out.println(Thread.currentThread().getName() 
                + " detected interruption, exiting");
                return;
            }
            counter++;

            if ( counter == 10 )
            {
                counter = 0;
                Thread.yield();
            }

            if ( numAt++ == numToFind )
            {
                System.out.println( "The target number, " + numToFind + ", has been found by " + Thread.currentThread().getName() + "." );
            }

            else
            {
                System.out.println( Thread.currentThread().getName() + " has analyzed the number " + ( numAt - 1 ) + " - not the target number." );
            }

        }   
    }
}
person Nathan Hughes    schedule 29.04.2016
comment
Благодаря этому функция shutdownNow() работает правильно, но я не могу вызвать ее сразу, иначе потоки мгновенно остановятся. Как мне вызвать shutdownNow(), когда номер найден? - person B. Freeman; 29.04.2016
comment
@B.Freeman: вы можете подождать с вызовом shutdownNow, пока не получите ответ. я сделал что-то подобное, но без исполнителя здесь. Но в этом случае я бы использовал Future и вызывал shutdownNow, как только будущее вернется. также здесь ответ с использованием Future и Callable. - person Nathan Hughes; 29.04.2016