คุณจะฆ่า a java.lang.Thread
ใน Java ได้อย่างไร?
ExecutorStatus
กับคำถามนี้: stackoverflow.com/questions/2275443/how-to-timeout-a-thread
คุณจะฆ่า a java.lang.Thread
ใน Java ได้อย่างไร?
ExecutorStatus
กับคำถามนี้: stackoverflow.com/questions/2275443/how-to-timeout-a-thread
คำตอบ:
ดูนี้ด้ายโดย Sun Thread.stop()
เกี่ยวกับเหตุผลที่พวกเขาเลิก มันมีรายละเอียดเกี่ยวกับสาเหตุที่เป็นวิธีที่ไม่ดีและสิ่งที่ควรทำเพื่อหยุดเธรดโดยทั่วไปได้อย่างปลอดภัย
วิธีที่พวกเขาแนะนำคือใช้ตัวแปรที่แชร์เป็นแฟล็กซึ่งขอให้เธรดพื้นหลังหยุด ตัวแปรนี้สามารถถูกตั้งค่าโดยวัตถุอื่นที่ร้องขอการยกเลิกเธรด
getConnection()
java.sql.DriverManager
หากการเชื่อมต่อใช้เวลานานเกินไปฉันพยายามที่จะฆ่าเธรดที่เกี่ยวข้องโดยการโทรThread.interrupt()
แต่มันจะไม่ส่งผลกระทบต่อเธรดเลย Thread.stop()
ทำงานอย่างไรก็ตามแม้ว่าพยากรณ์บอกว่ามันไม่ควรทำงานหากinterrupt()
ไม่ได้ ฉันสงสัยว่ามันทำงานได้อย่างไรและหลีกเลี่ยงการใช้วิธีที่เลิกใช้แล้ว
โดยทั่วไปคุณไม่ ..
คุณขอให้มันขัดจังหวะสิ่งที่มันทำโดยใช้Thread.interrupt () (ลิงค์ javadoc)
คำอธิบายที่ดีว่าเพราะเหตุใดใน javadoc ที่นี่ (ลิงค์ java technote)
interrupt()
เรียกเมธอด คำถามหลักเกี่ยวข้องกับการสร้างบันทึกสำหรับเธรดใหม่แต่ละชุด
ใน Java กระทู้ไม่ได้ฆ่าตาย แต่หยุดของด้ายที่จะทำในวิธีการสหกรณ์ เธรดถูกขอให้ยุติและจากนั้นเธรดสามารถปิดได้อย่างเรียบร้อย
บ่อยครั้งที่volatile boolean
ฟิลด์ถูกใช้ซึ่งเธรดจะตรวจสอบและยุติเป็นระยะเมื่อมีการตั้งค่าเป็นค่าที่สอดคล้องกัน
ฉันจะไม่ใช้ a boolean
เพื่อตรวจสอบว่าเธรดควรยุติหรือไม่ ถ้าคุณใช้volatile
เป็นตัวปรับแต่งข้อมูลนี้จะทำงานที่เชื่อถือได้ แต่ถ้ารหัสของคุณจะมีความซับซ้อนมากขึ้นแทนที่จะใช้วิธีการปิดกั้นอื่น ๆ ภายในwhile
วงก็อาจจะเกิดขึ้นว่ารหัสของคุณจะไม่ยุติที่ทุกคนหรืออย่างน้อยต้องใช้เวลานานเป็นคุณ อาจต้องการ
วิธีการบล็อกไลบรารีบางวิธีรองรับการหยุดชะงัก
ทุกเธรดมีสถานะบูลีนที่ถูกขัดจังหวะและคุณควรใช้มัน สามารถนำไปใช้ได้ดังนี้:
public void run() {
try {
while (!interrupted()) {
// ...
}
} catch (InterruptedException consumed)
/* Allow thread to exit */
}
}
public void cancel() { interrupt(); }
รหัสที่มาดัดแปลงมาจากJava Concurrency ในการปฏิบัติ เนื่องจากcancel()
วิธีนี้เป็นแบบสาธารณะคุณสามารถปล่อยให้เธรดอื่นเรียกใช้เมธอดนี้ตามที่คุณต้องการ
วิธีหนึ่งคือการตั้งค่าตัวแปรคลาสและใช้เป็น Sentinel
Class Outer {
public static volatile flag = true;
Outer() {
new Test().start();
}
class Test extends Thread {
public void run() {
while (Outer.flag) {
//do stuff here
}
}
}
}
ตั้งค่าตัวแปรคลาสภายนอกเช่น flag = true ในตัวอย่างด้านบน ตั้งค่าเป็นเท็จเพื่อ 'ฆ่า' เธรด
volatile
เพื่อให้แน่ใจว่าทำงานได้อย่างถูกต้องทุกที่ คลาสภายในไม่คงที่ดังนั้นแฟล็กควรเป็นตัวแปรอินสแตนซ์ ควรล้างค่าสถานะในวิธีการเข้าถึงเพื่อให้การดำเนินการอื่น ๆ (เช่นการขัดจังหวะ) สามารถทำได้ ชื่อ "flag" ไม่ใช่คำอธิบาย
มีวิธีที่คุณสามารถทำได้ แต่ถ้าคุณต้องใช้มันไม่ว่าคุณจะเป็นโปรแกรมเมอร์ที่ไม่ดีหรือคุณกำลังใช้รหัสที่เขียนโดยโปรแกรมเมอร์ที่ไม่ดี ดังนั้นคุณควรคิดถึงการหยุดเป็นโปรแกรมเมอร์ที่ไม่ดีหรือหยุดโดยใช้รหัสที่ไม่ดีนี้ วิธีนี้ใช้สำหรับสถานการณ์ที่ไม่มีทางอื่นเท่านั้น
Thread f = <A thread to be stopped>
Method m = Thread.class.getDeclaredMethod( "stop0" , new Class[]{Object.class} );
m.setAccessible( true );
m.invoke( f , new ThreadDeath() );
Thread.stop
แม้ว่ามันจะเลิก
Thread.stop
ทำสิ่งเดียวกัน แต่ตรวจสอบการเข้าถึงและการอนุญาต การใช้Thread.stop
ค่อนข้างชัดเจนและฉันจำไม่ได้ว่าทำไมฉันถึงใช้Thread.stop0
แทนสิ่งนั้น อาจจะThread.stop
ไม่ได้ผลกับกรณีพิเศษของฉัน (Weblogic บน Java 6) หรืออาจThread.stop
เป็นเพราะเลิกใช้แล้วทำให้เกิดการเตือน
ฉันต้องการเพิ่มข้อสังเกตหลายประการโดยอิงจากความคิดเห็นที่สะสมไว้
Thread.stop()
จะหยุดเธรดหากตัวจัดการความปลอดภัยอนุญาตThread.stop()
อันตราย. ต้องบอกว่าถ้าคุณกำลังทำงานในสภาพแวดล้อม JEE และคุณไม่สามารถควบคุมรหัสที่ถูกเรียกได้อาจจำเป็น เห็นทำไม Thread.stop เลิกใช้?stop()
สร้างThreadDeathError
ข้อผิดพลาดใหม่ในหัวข้อการโทรแล้วโยนข้อผิดพลาดนั้นบนเธรดเป้าหมาย ดังนั้นการติดตามสแต็กจึงไม่มีค่าstop()
ตรวจสอบกับผู้จัดการการรักษาความปลอดภัยและเรียกสายที่stop1()
เป็นรหัสเนทีฟstop0()
stop0()
Thread.stop()
ยังไม่ถูกลบ (แต่) แต่Thread.stop(Throwable)
ถูกลบใน Java 11 ( รายชื่อผู้รับจดหมาย , JDK-8204243 )Thread.stop()
ฉันจะลงคะแนนเสียงให้
ตัวอย่างเช่นคุณมีการดำเนินการที่ยาวนาน (เช่นคำขอเครือข่าย) สมมติว่าคุณกำลังรอการตอบกลับ แต่อาจต้องใช้เวลาและผู้ใช้ไปยัง UI อื่น เธรดที่รออยู่ตอนนี้ก) ไร้ประโยชน์ b) ปัญหาที่อาจเกิดขึ้นเพราะเมื่อเขาได้รับผลก็จะไร้ประโยชน์อย่างสมบูรณ์และเขาจะเรียกการเรียกกลับที่สามารถนำไปสู่จำนวนข้อผิดพลาด
ทั้งหมดนี้และเขาสามารถทำการประมวลผลการตอบสนองที่อาจรุนแรงของ CPU และคุณในฐานะนักพัฒนาไม่สามารถหยุดมันได้เพราะคุณไม่สามารถโยนif (Thread.currentThread().isInterrupted())
บรรทัดในรหัสทั้งหมดได้
ดังนั้นการไร้ความสามารถในการหยุดเธรดอย่างแรงมันก็แปลก
Thread.stop()
ได้อย่างปลอดภัย คุณยังไม่ได้ลงคะแนนThread.stop()
คุณจะขอให้ทุกคนที่ดำเนินการทุกอย่างที่อาจใช้เวลานานในการยกเลิกอย่างปลอดภัย และนั่นอาจเป็นความคิดที่ดี แต่ก็ไม่มีอะไรเกี่ยวข้องกับการนำไปใช้Thread.stop()
เป็นวิธีการทำแท้งที่ปลอดภัย เรามีอยู่แล้วinterrupt
สำหรับสิ่งนั้น
stop
และสรุปว่ามีการแก้ปัญหาไม่มีที่ทำงานได้ในทางเทคนิคที่ไม่ได้เลวร้ายยิ่งกว่าหึ
คำถามค่อนข้างคลุมเครือ หากคุณหมายถึง“ ฉันจะเขียนโปรแกรมอย่างไรเพื่อให้เธรดหยุดทำงานเมื่อฉันต้องการมัน” ดังนั้นคำตอบอื่น ๆ ที่หลากหลายควรเป็นประโยชน์ แต่ถ้าคุณหมายถึง“ฉันมีเหตุฉุกเฉินกับเซิร์ฟเวอร์ฉันไม่สามารถเริ่มต้นในขณะนี้และฉันก็ต้องด้ายโดยเฉพาะอย่างยิ่งที่จะตายมาสิ่งที่อาจ” jstack
แล้วคุณจะต้องเป็นเครื่องมือแทรกแซงเพื่อให้ตรงกับการตรวจสอบเครื่องมือเช่น
เพื่อจุดประสงค์นี้ฉันสร้างjkillthread ดูคำแนะนำสำหรับการใช้งาน
มีกรณีที่คุณกำลังเรียกใช้รหัสที่ไม่น่าเชื่อถือบางประเภท (ฉันมีสิ่งนี้เป็นการส่วนตัวโดยการอนุญาตให้สคริปต์ที่อัปโหลดสามารถทำงานในสภาพแวดล้อม Java ของฉันใช่มีสัญญาณเตือนความปลอดภัยดังขึ้นทุกที่ แต่เป็นส่วนหนึ่งของแอปพลิเคชัน) ในกรณีที่โชคร้ายนี้คุณเป็นคนแรก เพื่อเคารพสัญญาณบูลีนที่ทำงาน / ไม่ทำงานบางประเภท ความปลอดภัยที่ล้มเหลวเพียงอย่างเดียวของคุณคือการเรียกใช้เมธอด stop บนเธรดหากพูดว่ามันทำงานได้นานกว่าการหมดเวลาบางส่วน
แต่นี่เป็นเพียง "ดี" และไม่สมบูรณ์เพราะรหัสสามารถตรวจจับข้อผิดพลาด ThreadDeath (หรือข้อยกเว้นใด ๆ ที่คุณโยนอย่างชัดแจ้ง) และไม่รื้อฟื้นเหมือนเธรดสุภาพบุรุษที่ควรทำ ดังนั้นบรรทัดล่างคือ AFAIA จึงไม่มีความล้มเหลวที่แน่นอนอย่างปลอดภัย
ไม่มีทางที่จะฆ่าเธรดอย่างงดงามได้
คุณสามารถลองขัดจังหวะเธรดหนึ่งในกลยุทธ์ทั่วไปคือการใช้ยาพิษเพื่อส่งข้อความถึงเธรดเพื่อหยุดตัวเอง
public class CancelSupport {
public static class CommandExecutor implements Runnable {
private BlockingQueue<String> queue;
public static final String POISON_PILL = “stopnow”;
public CommandExecutor(BlockingQueue<String> queue) {
this.queue=queue;
}
@Override
public void run() {
boolean stop=false;
while(!stop) {
try {
String command=queue.take();
if(POISON_PILL.equals(command)) {
stop=true;
} else {
// do command
System.out.println(command);
}
} catch (InterruptedException e) {
stop=true;
}
}
System.out.println(“Stopping execution”);
}
}
}
BlockingQueue<String> queue=new LinkedBlockingQueue<String>();
Thread t=new Thread(new CommandExecutor(queue));
queue.put(“hello”);
queue.put(“world”);
t.start();
Thread.sleep(1000);
queue.put(“stopnow”);
โดยทั่วไปคุณจะไม่ฆ่าหยุดหรือขัดจังหวะเธรด (หรือตรวจสอบว่ามันถูกขัดจังหวะ ()) แต่ปล่อยให้มันยุติโดยธรรมชาติ
มันง่าย คุณสามารถใช้วนรอบใด ๆ ร่วมกับตัวแปรบูลีน (ระเหย) ภายในวิธีการ run () เพื่อควบคุมกิจกรรมของเธรด คุณยังสามารถกลับจากเธรดที่ใช้งานอยู่ไปยังเธรดหลักเพื่อหยุด
วิธีนี้คุณฆ่าเธรดอย่างงดงาม :)
ความพยายามในการยกเลิกเธรดอย่างกระทันหันนั้นเป็นที่รู้จักกันดีในด้านการเขียนโปรแกรมที่ไม่ดีและมีหลักฐานการออกแบบแอพพลิเคชั่นที่ไม่ดี เธรดทั้งหมดในแอปพลิเคชันแบบมัลติเธรดอย่างชัดเจนและโดยนัยแบ่งปันสถานะกระบวนการเดียวกันและถูกบังคับให้ร่วมมือกันเพื่อให้สอดคล้องกันมิฉะนั้นแอปพลิเคชันของคุณจะมีแนวโน้มที่จะเป็นโรคจิตซึ่งยากต่อการวินิจฉัย ดังนั้นจึงเป็นความรับผิดชอบของนักพัฒนาในการให้ความมั่นใจในความสอดคล้องดังกล่าวผ่านการออกแบบแอพพลิเคชั่นที่ระมัดระวังและชัดเจน
มีวิธีแก้ปัญหาหลักสองประการสำหรับการยุติการควบคุมเธรด:
คำอธิบายที่ดีและมีรายละเอียดของปัญหาที่เกี่ยวข้องกับการยกเลิกเธรดในทันทีรวมถึงตัวอย่างของการแก้ปัญหาที่ไม่ถูกต้องและเหมาะสมสำหรับการยกเลิกเธรดที่ควบคุมสามารถดูได้ที่นี่:
ฉันไม่ได้ขัดจังหวะการทำงานใน Android ดังนั้นฉันจึงใช้วิธีนี้ทำงานได้อย่างสมบูรณ์แบบ:
boolean shouldCheckUpdates = true;
private void startupCheckForUpdatesEveryFewSeconds() {
Thread t = new Thread(new CheckUpdates());
t.start();
}
private class CheckUpdates implements Runnable{
public void run() {
while (shouldCheckUpdates){
//Thread sleep 3 seconds
System.out.println("Do your thing here");
}
}
}
public void stop(){
shouldCheckUpdates = false;
}
'การฆ่าเธรด' ไม่ใช่วลีที่ถูกต้องที่จะใช้ นี่คือวิธีหนึ่งที่เราสามารถใช้งานเสร็จสมบูรณ์ / ออกของด้ายบนจะ:
Runnable ที่ฉันใช้:
class TaskThread implements Runnable {
boolean shouldStop;
public TaskThread(boolean shouldStop) {
this.shouldStop = shouldStop;
}
@Override
public void run() {
System.out.println("Thread has started");
while (!shouldStop) {
// do something
}
System.out.println("Thread has ended");
}
public void stop() {
shouldStop = true;
}
}
คลาสที่เรียกใช้:
public class ThreadStop {
public static void main(String[] args) {
System.out.println("Start");
// Start the thread
TaskThread task = new TaskThread(false);
Thread t = new Thread(task);
t.start();
// Stop the thread
task.stop();
System.out.println("End");
}
}
Thread.stop เลิกใช้แล้วเราจะหยุดเธรดใน java อย่างไร?
ใช้วิธีการขัดจังหวะและในอนาคตเพื่อขอยกเลิกเสมอ
Callable < String > callable = new Callable < String > () {
@Override
public String call() throws Exception {
String result = "";
try {
//assume below take method is blocked as no work is produced.
result = queue.take();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
return result;
}
};
Future future = executor.submit(callable);
try {
String result = future.get(5, TimeUnit.SECONDS);
} catch (TimeoutException e) {
logger.error("Thread timedout!");
return "";
} finally {
//this will call interrupt on queue which will abort the operation.
//if it completes before time out, it has no side effects
future.cancel(true);
}
public interface CustomCallable < T > extends Callable < T > {
void cancel();
RunnableFuture < T > newTask();
}
public class CustomExecutorPool extends ThreadPoolExecutor {
protected < T > RunnableFuture < T > newTaskFor(Callable < T > callable) {
if (callable instanceof CancellableTask)
return ((CancellableTask < T > ) callable).newTask();
else
return super.newTaskFor(callable);
}
}
public abstract class UnblockingIOTask < T > implements CustomCallable < T > {
public synchronized void cancel() {
try {
obj.close();
} catch (IOException e) {
logger.error("io exception", e);
}
}
public RunnableFuture < T > newTask() {
return new FutureTask < T > (this) {
public boolean cancel(boolean mayInterruptIfRunning) {
try {
this.cancel();
} finally {
return super.cancel(mayInterruptIfRunning);
}
}
};
}
}