Как выполнить остановку потока при вставке в базу данных на Java?

Этот вопрос продолжает этот вопрос.

Я пытаюсь остановить поток, который вставляет строки в базу данных, но я всегда получал исключение

Эта часть кода показывает логику моего потока

public void run() {
        String number = "";
        try {
            while (!Thread.currentThread().isInterrupted()) {
                number = generateNumber();
                database.insertOrUpdateRow(number);
            }
        } catch (SQLException ex) {
            LOGGER.error("exception while inserting number " + number + " " + ex.getMessage());
        }
    }

Я гуглил, как правильно остановить поток, и обнаружил, что мне нужно просто отметить, что поток остановлен. Итак, это то, что я получил

public boolean stop() {
        try {
            Set<Thread> threadSet = Thread.getAllStackTraces().keySet();
            for (Thread t : threadSet) {
                if (t != null) {
                    if (t.getName().contains("generate")) {
                        t.interrupt();
                        LOGGER.info(t.getName()+" is stopped");
                    }
                }
            }
        } catch (Exception e) {
            LOGGER.error("Exception when call stop: " + e.toString());
        }
        return true;
    }

Мой стек

[INFO] [qtp1804418913-32] INFO se.homework.hwbs.tasks.un.server.NumberQtyService
Impl - generate37 is stopped
[INFO] [generate37] ERROR se.homework.hwbs.tasks.un.server.threads.InsertRowThre
ad - exception while inserting number 34587 transaction rollback: serialization
failure
[INFO] [qtp1804418913-33] ERROR se.homework.hwbs.tasks.un.server.database.Databa
se - error select cnt by numberjava.sql.SQLTransactionRollbackException: transac
tion rollback: serialization failure
[INFO] [qtp1804418913-34] ERROR se.homework.hwbs.tasks.un.server.database.Databa
se - error select cnt by numberjava.sql.SQLTransactionRollbackException: transac
tion rollback: serialization failure

Поток останавливается, все работает, но эти исключения заставляют меня чувствовать себя плохо. Почему они случаются? Как остановить поток, когда я правильно работаю с базой данных? База данных HsqlDB.

2 ответа

Вместо того, чтобы перечислять потоки и выбирать один по имени, вы можете рассмотреть возможность использования переменной остановки в вашем потоке вставки, которой можно напрямую управлять.

Рассмотрим это GeneratorThread:

public class GeneratorThread  extends Thread {

    protected static volatile boolean stop;

    public static void stopExecution() {
        stop = true;
    }

    public GeneratorThread() {
        stop = false;
    }

    public void run() {
        String number = "";
        try {
            while (!stop) {
                number = generateNumber();
                database.insertOrUpdateRow(number);
            }
        } catch (SQLException ex) {
            //Any SQLException will terminate your thread. Is this wanted?!
            LOGGER.error("exception while inserting number " + number + " " + ex.getMessage());
        }
    }
}

Вы можете остановить это, позвонив GeneratorThread.stopExecution() который установит флаг в ложь, в результате чего текущий номер будет последним вставленным.

Конечно, это означает, что будет только один GeneratorThread когда-либо в вашем приложении.

Точно так же вы можете переосмыслить свое время и попытаться поймать позиции в беге. Этот поток заканчивается на любом исключении SQLException. Если вы хотите, чтобы поток работал, даже если есть (временные?) Ошибки, вы можете захотеть сделать

    while (!stop) {
        String number = "";
        try {
            number = generateNumber();
            database.insertOrUpdateRow(number);
        } catch (SQLException ex) {
            LOGGER.error("exception while inserting number " + number + " " + ex.getMessage());
        }
    }

Я объединил идеи @Jan и @Fildor.

Итак, это то, что я получил

public class GeneratingThread extends Thread {

private final Logger LOGGER = LoggerFactory.getLogger(InsertRowThread.class);
private final Database database;
private boolean stop = false;

public GeneratingThread(Database database) {
    this.database = database;
}

@Override
public void run() {
    String number = "";
    try {
        while (!stop) {
            number = generateNumber();
            database.insertOrUpdateRow(number);
        }
    } catch (SQLException ex) {
        LOGGER.error("exception while inserting number " + number + " " + ex.getMessage());
    }
}

public void stopThread() {
    this.stop = true;
}

private String generateNumber() {
    int number = ThreadLocalRandom.current().nextInt(0, 100000);
    String sb = Integer.toString(number);
    while (sb.length() < 5) {
        sb = "0" + sb;
    }
    return sb;
}
}

И это мое начало потока

private final List<GeneratingThread> generatingThreads = new ArrayList<>();
GeneratingThread thread = new GeneratingThread(db);
thread.start();
generatingThreads.add(thread);

И прекрати это

for (GeneratingThread gt : generatingThreads) {
        if (gt != null) {
            gt.stopThread();
            LOGGER.info("Thread is stopped");
        }
    }

Работал идеально для меня. Спасибо за обсуждение!

Другие вопросы по тегам