2010-07-26 35 views
32

Đoạn mã sau đây cố gắng đồng bộ hóa điều này.Tắt các chủ đề và người thi hành duyên dáng

Mã lặp mãi mãi và kiểm tra xem có bất kỳ yêu cầu đang chờ xử lý nào không. Nếu có, nó tạo ra một luồng mới để xử lý yêu cầu và gửi nó đến người thực thi. Một khi tất cả các chủ đề được thực hiện, nó ngủ trong 60 giây và một lần nữa kiểm tra các yêu cầu đang chờ xử lý.

public static void main(String a[]){ 
    //variables init code omitted 
    ExecutorService service = Executors.newFixedThreadPool(15); 
    ExecutorCompletionService<Long> comp = new ExecutorCompletionService<Long>(service); 
    while(true){ 
     List<AppRequest> pending = service.findPendingRequests(); 
     int noPending = pending.size(); 
     if (noPending > 0) { 
      for (AppRequest req : pending) { 
       Callable<Long> worker = new RequestThread(something, req); 
       comp.submit(worker); 
      } 
     } 
     for (int i = 0; i < noPending; i++) { 
      try { 
       Future<Long> f = comp.take(); 
       long name; 
       try { 
        name = f.get(); 
        LOGGER.debug(name + " got completed"); 
       } catch (ExecutionException e) { 
        LOGGER.error(e.toString()); 
       } 
      } catch (InterruptedException e) { 
       LOGGER.error(e.toString()); 
      } 
     } 
     TimeUnit.SECONDS.sleep(60); 
    } 

    } 

Câu hỏi của tôi là hầu hết các quá trình xử lý được thực hiện bởi các chủ đề này liên quan đến cơ sở dữ liệu. Và chương trình này sẽ chạy trên một cửa sổ máy. Điều gì sẽ xảy ra với các chủ đề này khi ai đó cố gắng tắt máy hoặc đăng xuất máy. Làm thế nào để gracefully tắt các chủ đề đang chạy và cũng là người thi hành.

Trả lời

55

Một trật tự tắt máy điển hình của một ExecutorService có thể trông như thế này:

final ExecutorService executor; 

Runtime.getRuntime().addShutdownHook(new Thread() { 
    public void run() { 
     executor.shutdown(); 
     if (!executor.awaitTermination(SHUTDOWN_TIME)) { //optional * 
      Logger.log("Executor did not terminate in the specified time."); //optional * 
      List<Runnable> droppedTasks = executor.shutdownNow(); //optional ** 
      Logger.log("Executor was abruptly shut down. " + droppedTasks.size() + " tasks will not be executed."); //optional ** 
     } 
    } 
}); 

* Bạn có thể đăng nhập rằng người thi hành vẫn có nhiệm vụ để xử lý sau khi chờ đợi thời gian bạn sẵn sàng chờ đợi.
** Bạn có thể cố gắng ép buộc nhân viên của người thực hiện Đề tài từ bỏ nhiệm vụ hiện tại của họ và đảm bảo họ không bắt đầu bất kỳ công việc nào còn lại.

Lưu ý rằng giải pháp ở trên sẽ hoạt động khi người dùng gây gián đoạn cho quy trình java của bạn hoặc khi ExecutorService chỉ chứa các chuỗi daemon. Nếu, thay vào đó, ExecutorService chứa các chuỗi không phải daemon chưa hoàn thành, JVM sẽ không cố gắng tắt máy và do đó các móc tắt máy sẽ không được gọi.

Nếu cố gắng tắt một quá trình như là một phần của vòng đời ứng dụng rời rạc (không phải dịch vụ) thì mã tắt sẽ không được đặt trong móc tắt nhưng tại vị trí thích hợp mà chương trình được thiết kế để chấm dứt.

+0

Đây là số lùi. Giả sử 'ExecutorService' là một trong những giá trị điển hình được trả về bởi các phương thức factory' Executors', các chủ đề sao lưu là các chuỗi không phải daemon. Móc tắt sẽ không được gọi cho đến khi các luồng đó thoát ra và điều đó sẽ không xảy ra cho đến khi 'ExecutorService' bị tắt. Giải pháp của bạn sẽ chỉ khi các chủ đề của người thực thi không phải là daemon hoặc nếu chương trình của bạn nhận được một người dùng bị gián đoạn. –

+0

OP yêu cầu cụ thể về trường hợp JVM được yêu cầu thực hiện tắt máy theo thứ tự. Bất kể, nội dung của câu trả lời là chính xác, một trong những chỉ cần không làm điều này trong một cái móc tắt để chấm dứt dịch vụ thi hành trước đó. –

+0

Cảm ơn bạn đã trả lời quá nhanh.Tôi đoán tôi đã bỏ lỡ một phần câu hỏi của họ. Bạn có thể thêm một '' 'thứ ba để làm rõ bit đó không? –

7

Cuốn sách "Java Concurrency in Practice" khẳng định:

7,4. JVM Shutdown

JVM có thể tắt theo cách có trật tự hoặc đột ngột . Yêu cầu tắt máy có trật tự khi chủ đề "bình thường" (nondaemon) chấm dứt, ai đó gọi System.exit, hoặc bằng các phương tiện nền tảng cụ thể khác (chẳng hạn như gửi SIGINT hoặc nhấn Ctrl-C). [...]

7.4.1. Shutdown Hooks

Để tắt máy, JVM đầu tiên bắt đầu tất cả các chốt tắt đã đăng ký. Móc tắt máy là các chủ đề chưa được đề xuất đã được đăng ký với Runtime.addShutdownHook. JVM làm cho không đảm bảo về thứ tự mà trong đó móc tắt máy được bắt đầu. Nếu bất kỳ chủ đề ứng dụng nào (daemon hoặc nondaemon) vẫn đang chạy ở thời gian tắt máy, chúng sẽ tiếp tục chạy đồng thời với quá trình tắt máy . Khi tất cả các chốt tắt đã hoàn thành , JVM có thể chọn chạy finalizers nếu runFinalizersOnExit là true và sau đó tạm dừng. JVM không làm cho cố gắng ngừng hoặc làm gián đoạn bất kỳ chủ đề ứng dụng nào vẫn còn chạy lúc tắt máy; chúng được đột ngột chấm dứt khi JVM ngừng hoạt động. Nếu tắt máy móc hoặc bộ hoàn thiện, thì quá trình tắt máy theo thứ tự "bị treo" và JVM phải được tắt đột ngột. [...]

Các bit quan trọng là, "The JVM làm cho không có nỗ lực để ngăn chặn hoặc gián đoạn bất kỳ xử lí ứng dụng vẫn đang chạy ở thời gian tắt máy;. Họ đột ngột chấm dứt khi JVM cuối cùng dừng" vì vậy tôi cho rằng kết nối với DB sẽ đột ngột chấm dứt, nếu không có móc tắt máy ở đó để làm sạch một cách duyên dáng (nếu bạn đang sử dụng các khung công tác, chúng thường cung cấp các móc tắt máy). Theo kinh nghiệm của tôi, phiên làm việc với DB có thể vẫn còn cho đến khi nó được hết thời gian bởi DB, v.v. khi ứng dụng. được chấm dứt mà không có móc như vậy.

2

Bạn có thể gọi shutdown() trên ExecutorService:

Ðồng một trật tự tắt máy, trong đó nhiệm vụ nộp trước đây là thực hiện, nhưng không có nhiệm vụ mới sẽ được chấp nhận.

hoặc bạn có thể gọi shutdownNow():

nỗ lực để ngăn chặn tất cả tích cực nhiệm vụ thực hiện, tạm dừng việc xử lý nhiệm vụ chờ đợi, và trả về một danh sách trong những nhiệm vụ đã được chờ thực hiện.

Không có đảm bảo nào ngoài cố gắng hết sức để ngăn chặn xử lý tích cực thực hiện các tác vụ. Ví dụ, việc triển khai điển hình sẽ hủy qua Thread.interrupt(), vì vậy bất kỳ tác vụ nào không phản hồi lại các ngắt có thể không bao giờ chấm dứt.

Mà một trong những bạn gọi phụ thuộc vào cách tồi tệ bạn muốn nó dừng lại ....

+0

Tôi đang gặp phải vấn đề sau trong ứng dụng web của mình. Làm cách nào để ngăn chặn rò rỉ bộ nhớ .http: //stackoverflow.com/questions/39166512/memory-leak-error-in-tomcat-server-even-after-removed-quartz Mã số liên quan – Vicky

5

Vì thêm móc tắt máy để gọi rõ ràng shutdown() không hoạt động đối với tôi, tôi đã tìm thấy giải pháp dễ dàng trong Google ổi: com.google.common.util.concurrent.MoreExecutors.getExitingExecutorService.

+1

Tuy nhiên, nó có một chút vấn đề vì 'MoreExecutors.getExitingExecutorService' chỉ chấp nhận trường hợp' ThreadPoolExecutor'. Kết quả là, bạn phải xác định thủ công các trình thực thi đó thay vì chỉ đơn giản gọi, ví dụ, 'Executors.newFixedThreadPool' trả về' ExecutorService'. – voo

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