Làm thế nào để bạn giết một java.lang.Thread
trong Java?
ExecutorStatus
câu hỏi này: stackoverflow.com/questions/2275443/how-to-timeout-a-thread
Làm thế nào để bạn giết một java.lang.Thread
trong Java?
ExecutorStatus
câu hỏi này: stackoverflow.com/questions/2275443/how-to-timeout-a-thread
Câu trả lời:
Xem chủ đềThread.stop()
này của Sun về lý do tại sao họ không tán thành . Nó đi vào chi tiết về lý do tại sao đây là một phương pháp tồi và nên làm gì để ngăn chặn các luồng một cách an toàn nói chung.
Cách họ đề xuất là sử dụng một biến được chia sẻ làm cờ yêu cầu dừng luồng nền. Biến này sau đó có thể được đặt bởi một đối tượng khác yêu cầu kết thúc luồng.
getConnection()
từ java.sql.DriverManager
. Nếu kết nối kết nối mất quá nhiều thời gian, tôi sẽ cố gắng giết luồng tương ứng bằng cách gọi Thread.interrupt()
nhưng nó hoàn toàn không ảnh hưởng đến luồng. Các Thread.stop()
tuy nhiên hoạt động, mặc dù oracle nói nó không nên làm việc nếu interrupt()
không. Tôi tự hỏi làm thế nào để nó hoạt động và tránh sử dụng phương pháp không dùng nữa.
Nói chung là bạn không ..
Bạn yêu cầu nó làm gián đoạn bất cứ điều gì nó đang làm bằng cách sử dụng Thread.interrupt () (liên kết javadoc)
Một lời giải thích tốt về lý do tại sao trong javadoc ở đây (liên kết java technote)
interrupt()
phương thức được gọi? Câu hỏi chính liên quan đến việc tạo nhật ký cho mỗi luồng mới.
Trong các luồng Java không bị giết, nhưng việc dừng một luồng được thực hiện theo cách hợp tác . Các chủ đề được yêu cầu chấm dứt và sau đó chủ đề có thể tắt một cách duyên dáng.
Thông thường một volatile boolean
trường được sử dụng mà luồng kiểm tra định kỳ và chấm dứt khi nó được đặt thành giá trị tương ứng.
Tôi sẽ không sử dụng một boolean
để kiểm tra xem các chủ đề nên chấm dứt . Nếu bạn sử dụng volatile
như một công cụ sửa đổi trường, điều này sẽ hoạt động đáng tin cậy, nhưng nếu mã của bạn trở nên phức tạp hơn, thay vào đó sử dụng các phương thức chặn khác trong while
vòng lặp, điều đó có thể xảy ra, rằng mã của bạn sẽ không chấm dứt hoặc ít nhất là mất nhiều thời gian hơn khi bạn có thể muốn.
Một số phương pháp thư viện chặn nhất định hỗ trợ gián đoạn.
Mỗi luồng đã có trạng thái ngắt cờ boolean và bạn nên sử dụng nó. Nó có thể được thực hiện như thế này:
public void run() {
try {
while (!interrupted()) {
// ...
}
} catch (InterruptedException consumed)
/* Allow thread to exit */
}
}
public void cancel() { interrupt(); }
Mã nguồn được điều chỉnh từ Java đồng thời trong thực tiễn . Vì cancel()
phương thức này là công khai, bạn có thể để một luồng khác gọi phương thức này như bạn muốn.
Một cách là bằng cách đặt một biến lớp và sử dụng nó như một trọng điểm.
Class Outer {
public static volatile flag = true;
Outer() {
new Test().start();
}
class Test extends Thread {
public void run() {
while (Outer.flag) {
//do stuff here
}
}
}
}
Đặt một biến lớp bên ngoài, tức là flag = true trong ví dụ trên. Đặt nó thành false để 'giết' chuỗi.
volatile
để đảm bảo nó hoạt động tốt ở mọi nơi. Lớp bên trong không tĩnh, do đó, cờ nên là một biến thể hiện. Cờ phải được xóa trong một phương thức truy cập để có thể thực hiện các hoạt động khác (như ngắt). Tên "cờ" không được mô tả.
Có một cách bạn có thể làm điều đó. Nhưng nếu bạn phải sử dụng nó, hoặc bạn là một lập trình viên tồi hoặc bạn đang sử dụng một mã được viết bởi các lập trình viên xấu. Vì vậy, bạn nên suy nghĩ về việc ngừng trở thành một lập trình viên tồi hoặc ngừng sử dụng mã xấu này. Giải pháp này chỉ dành cho các tình huống khi KHÔNG CÓ CÁCH KHÁC.
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
ngay cả khi nó không được chấp nhận.
Thread.stop
làm tương tự nhưng cũng kiểm tra quyền truy cập và quyền. Sử dụng Thread.stop
là khá rõ ràng và tôi không nhớ lý do tại sao tôi sử dụng Thread.stop0
thay vì đó. Có lẽ Thread.stop
không hoạt động cho trường hợp đặc biệt của tôi (Weblogic trên Java 6). Hoặc có thể vì Thread.stop
bị phản đối và gây ra cảnh báo.
Tôi muốn thêm một số quan sát, dựa trên các ý kiến đã tích lũy.
Thread.stop()
sẽ dừng một luồng nếu trình quản lý bảo mật cho phép.Thread.stop()
là nguy hiểm. Phải nói rằng, nếu bạn đang làm việc trong môi trường JEE và bạn không kiểm soát được mã được gọi, điều đó có thể là cần thiết; xem Tại sao Thread.stop không dùng nữa?stop()
tạo ra một ThreadDeathError
lỗi mới trên luồng gọi và sau đó ném lỗi đó vào luồng đích . Do đó, dấu vết ngăn xếp nói chung là vô giá trị.stop()
kiểm tra với người quản lý bảo mật và sau đó gọi các cuộc gọi stop1()
đó stop0()
. stop0()
là mã gốc.Thread.stop()
chưa bị xóa (nhưng), nhưng Thread.stop(Throwable)
đã bị xóa trong Java 11. ( danh sách gửi thư , JDK-8204243 )Tôi sẽ bình chọn cho Thread.stop()
.
Ví dụ, bạn có một hoạt động lâu dài (như yêu cầu mạng). Giả sử bạn đang chờ phản hồi, nhưng nó có thể mất thời gian và người dùng điều hướng đến giao diện người dùng khác. Chủ đề chờ đợi này bây giờ là một) vô dụng b) vấn đề tiềm ẩn bởi vì khi anh ta nhận được kết quả, nó hoàn toàn vô dụng và anh ta sẽ kích hoạt các cuộc gọi lại có thể dẫn đến một số lỗi.
Tất cả điều đó và anh ta có thể xử lý phản hồi có thể là CPU mạnh. Và bạn, với tư cách là một nhà phát triển, thậm chí không thể ngăn chặn nó, bởi vì bạn không thể némif (Thread.currentThread().isInterrupted())
các dòng trong tất cả các mã.
Vì vậy, không có khả năng mạnh mẽ để ngăn chặn một chủ đề nó kỳ lạ.
Thread.stop()
dù sao bạn cũng không thể gọi an toàn. Bạn không bỏ phiếu cho Thread.stop()
, bạn đang yêu cầu mọi người thực hiện mọi thao tác có thể mất nhiều thời gian để hủy bỏ an toàn. Và đó cũng có thể là một ý tưởng tốt, nhưng nó không liên quan gì đến việc thực hiện Thread.stop()
như là cách để yêu cầu phá thai an toàn. Chúng tôi đã có interrupt
cho điều đó.
stop
.
Câu hỏi khá mơ hồ. Nếu bạn có ý nghĩa là làm thế nào để tôi viết một chương trình để một luồng ngừng chạy khi tôi muốn nó đến thì các phản hồi khác sẽ hữu ích. Nhưng nếu bạn có nghĩa là tôi có một trường hợp khẩn cấp với một máy chủ thì tôi không thể khởi động lại ngay bây giờ và tôi chỉ cần một luồng cụ thể để chết, hãy đến những gì có thể, sau đó bạn cần một công cụ can thiệp để khớp với các công cụ giám sát như thế nào jstack
.
Với mục đích này, tôi đã tạo ra jkillthread . Xem hướng dẫn sử dụng.
Tất nhiên có trường hợp bạn đang chạy một số loại mã không hoàn toàn đáng tin cậy. (Cá nhân tôi có điều này bằng cách cho phép các tập lệnh được tải lên thực thi trong môi trường Java của tôi. Vâng, có tiếng chuông báo động bảo mật vang lên ở mọi nơi, nhưng đó là một phần của ứng dụng.) Trong trường hợp không may này, trước hết bạn chỉ hy vọng bằng cách hỏi người viết kịch bản để tôn trọng một số loại tín hiệu chạy / không chạy boolean. An toàn thất bại duy nhất của bạn là gọi phương thức dừng trên luồng nếu, giả sử, nó chạy lâu hơn thời gian chờ.
Nhưng, đây chỉ là "đàng hoàng", và không tuyệt đối, bởi vì mã có thể bắt lỗi ThreadDeath (hoặc bất kỳ ngoại lệ nào bạn ném rõ ràng), và không nghĩ lại như một chủ đề lịch sự cần phải làm. Vì vậy, điểm mấu chốt là AFAIA không có sự thất bại tuyệt đối an toàn.
Không có cách nào để duyên dáng giết chết một chủ đề.
Bạn có thể cố gắng làm gián đoạn chuỗi, một chiến lược chung là sử dụng một viên thuốc độc để nhắn tin cho chuỗi để tự dừng lại
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”);
Nói chung, bạn không giết, dừng hoặc ngắt một chuỗi (hoặc kiểm tra xem nó bị gián đoạn ()), nhưng hãy để nó chấm dứt một cách tự nhiên.
Nó đơn giản. Bạn có thể sử dụng bất kỳ vòng lặp nào cùng với biến boolean (dễ bay hơi) bên trong phương thức run () để kiểm soát hoạt động của luồng. Bạn cũng có thể quay lại từ luồng hoạt động đến luồng chính để dừng nó.
Bằng cách này, bạn duyên dáng giết một chủ đề :).
Nỗ lực chấm dứt chủ đề đột ngột là thực tiễn lập trình xấu nổi tiếng và bằng chứng về thiết kế ứng dụng kém. Tất cả các luồng trong ứng dụng đa luồng đều chia sẻ một cách rõ ràng và ngầm chia sẻ cùng một trạng thái quy trình và buộc phải hợp tác với nhau để giữ cho nó nhất quán, nếu không ứng dụng của bạn sẽ dễ bị lỗi rất khó chẩn đoán. Vì vậy, trách nhiệm của nhà phát triển là đảm bảo sự nhất quán như vậy thông qua thiết kế ứng dụng cẩn thận và rõ ràng.
Có hai giải pháp đúng cho việc chấm dứt chủ đề được kiểm soát:
Có thể tìm thấy giải thích tốt và chi tiết về các vấn đề liên quan đến việc chấm dứt các luồng đột ngột cũng như các ví dụ về các giải pháp sai và đúng cho việc chấm dứt các luồng được kiểm soát tại đây:
Dưới đây là một vài bài đọc hay về chủ đề này:
Tôi đã không làm gián đoạn hoạt động trong Android, vì vậy tôi đã sử dụng phương pháp này, hoạt động hoàn hảo:
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;
}
'Giết một chủ đề' không phải là cụm từ phù hợp để sử dụng. Đây là một cách chúng ta có thể thực hiện hoàn thành / thoát duyên dáng của chuỗi theo ý muốn:
Runnable mà tôi đã sử dụng:
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;
}
}
Lớp kích hoạt:
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 không được dùng nữa, làm thế nào để chúng ta dừng một chủ đề trong java?
Luôn sử dụng phương thức ngắt và tương lai để yêu cầu hủy
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);
}
}
};
}
}