2009-12-10 59 views
45

Tôi đang gặp khó khăn trong việc tìm cách bắt đầu, dừng và khởi động lại một chuỗi trong Java.Làm thế nào để bắt đầu/dừng/khởi động lại một chuỗi trong Java?

Cụ thể, tôi có một lớp Task (hiện đang thực hiện Runnable) trong một tệp Task.java. Ứng dụng chính của tôi cần để có thể bắt đầu nhiệm vụ này trên một sợi, STOP (giết) các chủ đề khi nó cần, và đôi khi KILL & RESTART các chủ đề ...

nỗ lực đầu tiên của tôi là với ExecutorService nhưng tôi có thể ' t dường như tìm một cách để nó khởi động lại một nhiệm vụ. Khi tôi sử dụng .shutdownnow() bất kỳ cuộc gọi nào trong tương lai tới .execute() không thành công vì ExecutorService là "tắt" ...

Vì vậy, làm cách nào tôi có thể thực hiện việc này?

+0

Đối với câu hỏi này bạn cũng có thể tham khảo: http://stackoverflow.com/questions/22937592/resume-interrupted-thread – artiethenoble

Trả lời

39

Khi chuỗi dừng, bạn không thể khởi động lại. Tuy nhiên, không có gì ngăn bạn tạo và bắt đầu một chuỗi mới.

Tùy chọn 1: Tạo chủ đề mới thay vì cố khởi động lại.

Tùy chọn 2: Thay vì để dừng chuỗi, hãy chờ và sau đó khi nhận được thông báo, bạn có thể cho phép nó hoạt động trở lại. Bằng cách này, các chủ đề không bao giờ dừng lại và sẽ không bao giờ cần phải được khởi động lại.

Chỉnh sửa dựa trên nhận xét:

Để "giết" các chủ đề bạn có thể làm một cái gì đó như sau.

yourThread.setIsTerminating(true); // tell the thread to stop 
yourThread.join(); // wait for the thread to stop 
+0

Đáng buồn là tôi phải giết/khởi động lại ... Tôi không có toàn quyền kiểm soát nội dung của thread và cho tình hình của tôi nó đòi hỏi phải khởi động lại ... Vì vậy, tạo một cái mới là tốt ... nhưng làm thế nào để giết cái hiện tại đầu tiên? – Shaitan00

+0

Nếu bạn thực sự muốn 'giết' chủ đề không bao giờ dựa hoặc cố gắng sử dụng bất kỳ phương pháp api nào có vẻ như vậy, ví dụ kill() stop() destroy(). Thay vào đó, khi Taylor đề xuất xem cờ bị gián đoạn: khi (! Thread.currentThread(). IsInterrupted()) {...} Khi chuỗi bị gián đoạn, hãy dọn sạch mọi chức năng trong chuỗi đó và thoát ra khỏi chạy phương thức và bắt đầu một chuỗi mới. –

+0

Tôi giả sử có một vòng lặp trong chuỗi của bạn để nó có thể kiểm tra cờ để xem liệu chuỗi có nên dừng hoặc tiếp tục thực thi hay không. –

0

Có sự khác biệt giữa tạm dừng chuỗi và dừng/giết nó. Nếu dừng lại cho bạn có nghĩa là giết chết các chủ đề, sau đó khởi động lại chỉ đơn giản là có nghĩa là tạo ra một sợi mới và tung ra.

Có các phương pháp để tiêu diệt chủ đề từ một chủ đề khác (ví dụ: người sinh ra của bạn), nhưng chúng không an toàn nói chung. Nó có thể an toàn hơn nếu luồng của bạn liên tục kiểm tra một số cờ để xem nó có tiếp tục không (tôi giả sử có một số vòng lặp trong luồng của bạn), và có "bộ điều khiển" bên ngoài thay đổi trạng thái của lá cờ đó.

Bạn có thể xem chi tiết một chút trong: http://java.sun.com/j2se/1.4.2/docs/guide/misc/threadPrimitiveDeprecation.html

Tôi có thể hỏi tại sao bạn muốn để diệt các sợi và khởi động lại nó? Tại sao không chỉ cần chờ đợi cho đến khi dịch vụ của nó là cần thiết một lần nữa? Java có cơ chế đồng bộ chính xác cho mục đích đó. Các chủ đề sẽ được ngủ cho đến khi bộ điều khiển thông báo cho nó để tiếp tục thực hiện.

0

Nếu tác vụ của bạn đang thực hiện một loại hành động nào đó trong vòng lặp thì có cách để tạm dừng/khởi động lại quá trình xử lý, nhưng tôi nghĩ nó sẽ nằm ngoài API Thread hiện đang cung cấp. Nếu một quá trình bắn duy nhất của tôi, tôi không biết bất kỳ cách nào để tạm ngưng/khởi động lại mà không chạy vào API đã không được chấp nhận hoặc không được phép nữa.

Đối với các quy trình vòng lặp, cách dễ nhất tôi có thể nghĩ là mã sinh ra Nhiệm vụ khởi tạo một ReentrantLock và chuyển nó cho công việc, cũng như giữ một tham chiếu. Mỗi khi Task chuyển sang vòng lặp của nó, nó sẽ cố gắng khóa trên thể hiện ReentrantLock và khi vòng lặp hoàn thành nó sẽ mở khóa. Bạn có thể muốn đóng gói tất cả thử/cuối cùng này, đảm bảo rằng bạn đã bỏ khóa ở cuối vòng lặp, ngay cả khi một ngoại lệ được ném ra.

Nếu bạn muốn tạm dừng tác vụ, chỉ cần thử khóa từ mã chính (vì bạn giữ một tham chiếu hữu ích). Điều này sẽ làm là chờ cho vòng lặp hoàn thành và không để cho nó bắt đầu lặp lại khác (vì thread chính đang giữ một khóa). Để khởi động lại luồng chỉ đơn giản là mở khóa từ mã chính, điều này sẽ cho phép nhiệm vụ tiếp tục các vòng lặp của nó.

Để dừng vĩnh viễn chuỗi, tôi sẽ sử dụng API thông thường hoặc để lại cờ trong Task và setter cho cờ (giống như stopImmediately). Khi vòng lặp gặp phải giá trị thực cho cờ này, nó dừng xử lý và hoàn thành phương thức chạy.

+0

Đáng buồn là chủ đề đang chờ (nghe) cho lưu lượng truy cập, đó là sự kiện đồng bộ chặn ... do đó không có "vòng lặp" – Shaitan00

7

Đánh giá java.lang.Thread.

Để bắt đầu hoặc khởi động lại (một lần một sợi được dừng lại, bạn không thể khởi động lại rằng chủ đề tương tự, nhưng nó không quan trọng, chỉ cần tạo ra một Thread dụ mới):

// Create your Runnable instance 
Task task = new Task(...); 

// Start a thread and run your Runnable 
Thread t = new Thread(task); 

Để ngăn chặn nó, có một phương pháp trên cá thể Task của bạn đặt cờ để thông báo phương thức run để thoát; trở về từ run thoát khỏi chuỗi. Nếu mã gọi của bạn cần phải biết các chủ đề thực sự đã dừng lại trước khi nó trở lại, bạn có thể sử dụng join:

// Tell Task to stop 
task.setStopFlag(true); 

// Wait for it to do so 
t.join(); 

Về việc khởi động lại: Mặc dù một Thread không thể được khởi động lại, bạn có thể tái sử dụng Runnable dụ của bạn với một mới thread nếu nó có trạng thái và bạn muốn giữ lại; điều tương tự. Chỉ cần đảm bảo rằng Runnable của bạn được thiết kế để cho phép nhiều cuộc gọi đến run.

+0

Đáng buồn là luồng đang chờ (đang nghe) cho lưu lượng truy cập, đó là sự kiện đồng bộ chặn .. Vì vậy, không có "vòng lặp" trong vòng chạy ... – Shaitan00

+2

@ Shaitan00: Nếu bạn đang nói về một 'ServerSocket' chặn trên một cuộc gọi' accept', sau đó chỉ cần có 'setStopFlag' gọi' close' trên socket. Lệnh 'accept' sẽ bỏ chặn bằng cách ném một' SocketException'. Bất cứ điều gì khác mà khối sẽ gần như chắc chắn có một chế độ thoát tương tự. –

1

Như đã nói bởi Taylor L, bạn không thể "dừng" một chuỗi (bằng cách gọi một phương thức đơn giản) do thực tế là nó có thể khiến hệ thống của bạn ở trạng thái không ổn định vì luồng gọi bên ngoài có thể không biết đang diễn ra bên trong chuỗi của bạn.

Với điều này đã nói, cách tốt nhất để "dừng" một chuỗi là để chủ đề luôn chú ý đến chính nó và để cho nó biết và hiểu khi nào nó nên dừng lại.

+0

Nhưng chính bản thân luồng đó đang chặn việc nghe. Đối với lưu lượng mạng ... nó không thực sự lặp lại cho đến khi nó nhận được một cái gì đó .... Vì vậy, hãy gửi một thông điệp giả để "tung vòng lặp vào bánh răng" và đặt cờ? – Shaitan00

3

Bạn không thể khởi động lại chuỗi sao cho tùy chọn tốt nhất là lưu trạng thái hiện tại của đối tượng tại thời điểm dừng và khi thao tác cần tiếp tục đối tượng đó, bạn có thể tạo lại đối tượng đó bằng cách lưu và sau đó bắt đầu chủ đề mới.

Hai bài viết này Swing WorkerConcurrency có thể giúp bạn xác định giải pháp tốt nhất cho sự cố của bạn.

+0

@ ChadNC- Nghe hay đấy. Bạn có thể hướng dẫn tôi thêm về cách lưu trạng thái hiện tại của đối tượng và sau đó tiếp tục. – user2821894

8

Không thể chấm dứt chuỗi trừ khi mã đang chạy trong chuỗi đó kiểm tra và cho phép chấm dứt.

Bạn nói: "Đáng buồn là tôi phải giết/khởi động lại nó ... Tôi không hoàn toàn kiểm soát các nội dung của chủ đề và hoàn cảnh của ta nó đòi hỏi khởi động lại"

Nếu các nội dung của chủ đề không cho phép chấm dứt hoạt động của nó thì bạn không thể chấm dứt chuỗi đó.

Trong bài của bạn, bạn nói: "Nỗ lực đầu tiên của tôi là với ExecutorService nhưng tôi dường như không thể tìm thấy một cách để nó khởi động lại một nhiệm vụ Khi tôi sử dụng .shutdownnow() ...."

Nếu bạn nhìn vào nguồn của "shutdownnow" nó chỉ chạy qua và ngắt các luồng đang chạy.Điều này sẽ không dừng việc thực thi của chúng, trừ khi mã trong các luồng đó kiểm tra xem nó có bị vô hiệu hóa hay không, và nếu vậy, hãy ngừng thực thi chính nó. Vì vậy, shutdownnow có lẽ không làm những gì bạn nghĩ.

Hãy để tôi minh họa cho những gì tôi có nghĩa là khi tôi nói rằng các nội dung của chủ đề phải cho phép cho chủ đề đó để được chấm dứt:

myExecutor.execute(new Runnable() { 
public void run() { 
    while (true) { 
    System.out.println("running"); 
    } 
} 
}); 
myExecutor.shutdownnow(); 

chủ đề đó sẽ tiếp tục chạy mãi mãi, mặc dù shutdownnow được gọi, bởi vì nó không bao giờ kiểm tra xem nó có bị chấm dứt hay không. chủ đề này, tuy nhiên, sẽ đóng cửa:

myExecutor.execute(new Runnable() { 
public void run() { 
    while (!Thread.interrupted()) { 
    System.out.println("running"); 
    } 
} 
}); 
myExecutor.shutdownnow(); 

Kể từ chủ đề này kiểm tra xem có hay không nó đã bị gián đoạn/tắt/chấm dứt.

Vì vậy, nếu bạn muốn một chủ đề mà bạn có thể tắt, bạn cần phải chắc chắn rằng nó kiểm tra xem nó đã bị gián đoạn hay chưa. Nếu bạn muốn một chủ đề mà bạn có thể "tắt" và "khởi động lại", bạn có thể thực hiện một runnable có thể thực hiện các nhiệm vụ mới như đã được đề cập trước đó.

Tại sao bạn không thể tắt một chuỗi đang chạy? Vâng tôi thực sự nói dối, bạn có thể gọi "yourThread.stop()" nhưng tại sao đây là một ý tưởng tồi? Các chủ đề có thể được trong một đồng bộ (hoặc phần quan trọng khác, nhưng chúng tôi sẽ giới hạn mình để thiết lập bảo vệ bởi từ khóa syncrhonized ở đây) phần mã khi bạn dừng nó. khối synch được cho là được thực hiện trong toàn bộ của họ và chỉ bởi một sợi trước khi được truy cập bởi một số chủ đề khác. Nếu bạn dừng một luồng ở giữa khối đồng bộ, sự bảo vệ được đưa vào vị trí bởi khối đồng bộ sẽ bị vô hiệu và chương trình của bạn sẽ đi vào trạng thái không xác định. Các nhà phát triển tạo các công cụ trong khối đồng bộ để giữ mọi thứ đồng bộ, nếu bạn sử dụng threadInstance.stop() bạn phá hủy ý nghĩa đồng bộ hóa, những gì nhà phát triển của mã đó đang cố hoàn thành và cách nhà phát triển của mã đó mong đợi các khối được đồng bộ hóa của mình hành xử.

-1

Tôi hoàn toàn không đồng ý với xác nhận quyền sở hữu "bạn không thể 'dừng' một chuỗi". Đây là một cái nhìn thiển cận về một vấn đề hóc búa. Tại sao?

Kiểm tra thường xuyên cờ bị gián đoạn thực sự không có gì khác ngoài hình thức chờ đợi bận rộn với quyết định khó khăn "khi nào cần kiểm tra cờ và tần suất". Có thể rất xấu hoặc không thể trả lời. Chủ đề lớp học cũng có phương thức "dừng (Throwable throwable)" mà tiếc là không được chấp nhận những gì tôi từ chối sâu sắc. Cho phương thức run() với phần thân của nó trong câu lệnh try-catch-finally-end: Tại sao OK rằng bất kỳ câu lệnh nào (từ bên trong cơ thể) có thể ném bất kỳ ngoại lệ được kiểm tra hoặc bỏ chọn nào trong khi yêu cầu dừng (new MyRuntimeException))) từ bên ngoài có thể không? Có thật sự bất ngờ từ bên ngoài không? Sau đó, những gì về RetExown bất ngờ RuntimeExceptions mà hiếm khi bị bắt vì chúng thường không rõ? Cuối cùng, các điều khoản bắt phải đối phó với ngoại lệ - cho dù đó là từ bên trong hay từ bên ngoài. Và khối cuối cùng có thể dọn dẹp. Tôi hy vọng, mọi người sẽ nghĩ về vấn đề thiết kế đó một lần nữa.

Tôi nghĩ rằng một chuỗi có thể chết (bằng cách tự chấm dứt) hoặc bị giết (ngay lập tức chấm dứt với ngoại lệ).

-1

Đôi khi nếu một Thread được bắt đầu và nó nạp một lớp nhược điểm động được chế biến với nhiều Thread/currentThread giấc ngủ bị gián đoạn trong khi bỏ qua Exception catch (es), một ngắt có thể không đủ để hoàn toàn thoát thực hiện.

Trong trường hợp đó, chúng ta có thể cung cấp các ngắt vòng lặp dựa trên:

while(th.isAlive()){ 
    log.trace("Still processing Internally; Sending Interrupt;"); 
    th.interrupt(); 
    try { 
     Thread.currentThread().sleep(100); 
    } catch (InterruptedException e) { 
     e.printStackTrace(); 
    } 
} 
0
You can start a thread like: 

    Thread thread=new Thread(new Runnable() { 
       @Override 
       public void run() { 
        try { 
         //Do you task 
        }catch (Exception ex){ 
         ex.printStackTrace();} 
       } 
      }); 
thread.start(); 

To stop a Thread: 

    thread.join();//it will kill you thread 

    //if you want to know whether your thread is alive or dead you can use 
System.out.println("Thread is "+thread.isAlive()); 

của nó nên tạo một chủ đề mới hơn là khởi động lại nó.

Các vấn đề liên quan