Как выполнить остановку потока при вставке в базу данных на 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");
}
}
Работал идеально для меня. Спасибо за обсуждение!