2008-12-23 49 views
13

Tôi có một chương trình liên tục thăm dò ý kiến ​​cơ sở dữ liệu để thay đổi giá trị của một số trường. Nó chạy ở chế độ nền và hiện đang sử dụng phương thức sleep (true) và sleep() để thiết lập khoảng thời gian. Tôi tự hỏi nếu đây là một thực hành tốt? Và, điều gì có thể là cách hiệu quả hơn để thực hiện điều này? Chương trình có nghĩa là để chạy mọi lúc.Vòng lặp Java và Chủ đề!

Do đó, cách duy nhất để dừng chương trình là phát hành lệnh giết trên ID tiến trình. Chương trình có thể đang ở giữa cuộc gọi JDBC. Làm thế nào tôi có thể đi về việc chấm dứt nó một cách duyên dáng hơn? Tôi hiểu rằng tùy chọn tốt nhất là tạo ra một số loại chiến lược thoát bằng cách sử dụng cờ sẽ được kiểm tra định kỳ theo luồng. Nhưng, tôi không thể nghĩ ra một cách/điều kiện thay đổi giá trị của lá cờ này. Bất kỳ ý tưởng?

Trả lời

12

Tôi tự hỏi đây có phải là phương pháp hay không?

No. Không tốt. Đôi khi, đó là tất cả những gì bạn có, nhưng nó không tốt.

Và, cách nào hiệu quả hơn để triển khai tính năng này?

Làm cách nào để mọi thứ vào cơ sở dữ liệu ngay từ đầu?

Thay đổi tốt nhất là sửa các chương trình chèn/cập nhật cơ sở dữ liệu để thực hiện các yêu cầu đi đến cơ sở dữ liệu và chương trình của bạn. Một chủ đề JMS là tốt cho loại điều này.

Thay đổi tốt nhất tiếp theo là thêm trình kích hoạt vào cơ sở dữ liệu để enqueue mỗi sự kiện chèn/cập nhật vào hàng đợi. Hàng đợi có thể nạp một chủ đề JMS (hoặc hàng đợi) để chương trình của bạn xử lý.

Gói giảm giá là vòng lặp bỏ phiếu của bạn.

Vòng lặp bỏ phiếu của bạn, tuy nhiên, không nên hoạt động bình thường. Nó sẽ thả một thông điệp vào một hàng đợi cho một số quá trình JDBC khác để làm việc. Yêu cầu chấm dứt là một thông báo khác có thể được đưa vào hàng đợi JMS. Khi chương trình của bạn nhận được thông báo chấm dứt, nó hoàn toàn phải được hoàn thành với yêu cầu JDBC trước và có thể dừng một cách duyên dáng.

Trước khi thực hiện bất kỳ điều này, hãy xem các giải pháp ESB. Mặt trời là JCAPS hoặc TIBCO đã có. Một mã nguồn mở ESB như Mulesource hoặc Jitterbit có thể đã có chức năng này đã được xây dựng và thử nghiệm.

+0

+1 cho câu trả lời toàn diện! –

8

Đây thực sự là vấn đề quá lớn để trả lời hoàn toàn ở định dạng này. Làm ơn cho bạn và mua Java Concurrency in Practice. Không có tài nguyên nào tốt hơn cho đồng thời trên nền tảng Java 5+ ngoài kia. Có toàn bộ chương dành cho chủ đề này.

Về chủ đề giết quá trình của bạn trong suốt cuộc gọi JDBC, điều đó sẽ ổn. Tôi tin rằng có những vấn đề với việc gián đoạn một cuộc gọi JDBC (trong đó bạn có thể không?) Nhưng đó là một vấn đề khác nhau.

+1

+1 Nếu bạn tìm thấy cuốn sách Goetz một chút áp đảo (tôi đã làm lúc đầu, có rất nhiều thông tin trong đó) tôi khuyên bạn nên đọc Java Threads 3rd edition để giới thiệu easer với nhiều mã hơn. – blank

+0

Có bản tóm tắt cho câu hỏi cụ thể này không? Giống như "sử dụng lớp này thay thế"? Hay gì đó? – OscarRyz

2

Thiết lập trình xử lý tín hiệu cho SIGTERM đặt cờ báo cho vòng lặp của bạn thoát khỏi lần tiếp theo.

+0

"Thiết lập trình xử lý tín hiệu cho SIGTERM" Bạn làm như thế nào? – OscarRyz

+0

Trình xử lý tín hiệu java của google '. – chaos

0

Nếu đó là ứng dụng của bạn và bạn có thể sửa đổi nó, bạn có thể:

  • Làm cho nó đọc một tập tin
  • đọc cho giá trị của một lá cờ.
  • Khi bạn muốn xóa nó, bạn chỉ cần sửa đổi tệp và ứng dụng sẽ thoát ra một cách duyên dáng.

Không cần phải làm việc chăm chỉ hơn thế.

+0

Vì đó là một vòng lặp while với khoảng thời gian khoảng 8 giây, IO liên quan đến việc đọc tệp sẽ khá nhiều. – Epitaph

3

Lưu ý rằng một Timer (hoặc tương tự) sẽ tốt hơn ở chỗ bạn ít nhất có thể tái sử dụng nó và để cho nó làm với tất cả các chi tiết của giấc ngủ, lịch trình, xử lý ngoại lệ, vv ...

Có nhiều lý do khiến ứng dụng của bạn có thể chết. Đừng tập trung vào chỉ một.

Nếu nó thậm chí về mặt lý thuyết có thể cho JDBC của bạn làm việc để lại những thứ trong một trạng thái nửa chính xác, sau đó bạn có một lỗi bạn nên sửa chữa. Tất cả công việc DB của bạn phải ở trong một giao dịch. Nó nên đi hoặc không đi.

1

Về câu hỏi "Chương trình có thể đang ở giữa cuộc gọi JDBC. Làm thế nào tôi có thể đi về việc chấm dứt nó một cách duyên dáng hơn?" - xem How can I abort a running jdbc transaction?

Lưu ý rằng sử dụng bình chọn với sleep() hiếm khi giải pháp đúng - được triển khai không đúng cách, nó có thể kết thúc việc hogging tài nguyên CPU (bộ lập lịch trình JVM kết thúc chi tiêu số lượng thời gian ngủ và thức dậy thread).

3

Đây là Java. Chuyển quá trình xử lý của bạn sang chuỗi thứ hai. Bây giờ bạn có thể

  • Đọc từ stdin trong vòng lặp. Nếu ai đó nhập "QUIT", hãy đặt cờ trong khi thành false và thoát.
  • Tạo khung AWT hoặc Swing bằng nút STOP.
  • Giả sử bạn là một daemon Unix và tạo một ổ cắm máy chủ. Đợi ai đó mở ổ cắm và gửi "QUIT". (Điều này có thêm tiền thưởng mà bạn có thể thay đổi giấc ngủ thành một lựa chọn với thời gian chờ.)

Phải có hàng trăm biến thể về điều này.

0

tôi đã tạo ra một lớp dịch vụ trong thư viện tiện ích của công ty hiện tại của tôi đối với những loại vấn đề:

public class Service implements Runnable { 

    private boolean shouldStop = false; 

    public synchronized stop() { 
     shouldStop = true; 
     notify(); 
    } 

    private synchronized shouldStop() { 
     return shouldStop; 
    } 

    public void run() { 
     setUp(); 
     while (!shouldStop()) { 
      doStuff(); 
      sleep(60 * 1000); 
     } 
    } 

    private synchronized sleep(long delay) { 
     try { 
      wait(delay); 
     } catch (InterruptedException ie1) { 
      /* ignore. */ 
     } 
    } 

} 

Tất nhiên điều này còn xa mới hoàn toàn nhưng bạn sẽ nhận được các ý chính. Điều này sẽ cho phép bạn chỉ cần gọi phương thức stop() khi bạn muốn chương trình dừng lại và chương trình sẽ thoát hoàn toàn.

+0

Nhận xét nhỏ - xử lý InterruptedException - xem http://www-128.ibm.com/developerworks/java/library/j-jtp05236.html – noahlz

+0

Cảm ơn bạn đã liên kết! Bài báo tuyệt vời! –

6

Như những người khác đã nói, thực tế là bạn phải thăm dò ý kiến ​​có thể là dấu hiệu của một vấn đề sâu hơn với thiết kế hệ thống của bạn ... nhưng đôi khi đó là cách nó đi, vì vậy ...

Nếu bạn muốn xử lý "giết chết" quá trình này một cách duyên dáng hơn một chút, bạn có thể cài đặt một cái móc shutdown được gọi là khi bạn nhấn tổ hợp phím Ctrl + C:

volatile boolean stop = false; 

Runtime.getRuntime().addShutdownHook(new Thread("shutdown thread") { 

    public void run() { 

     stop = true; 
    } 
}); 

sau đó định kỳ kiểm tra biến dừng.

Một giải pháp thanh lịch hơn là để chờ đợi vào một sự kiện:

boolean stop = false; 

final Object event = new Object(); 

Runtime.getRuntime().addShutdownHook(new Thread("shutdown thread") { 

    public void run() { 

     synchronized(event) { 

      stop = true; 
      event.notifyAll(); 
     } 
    } 
}); 

// ... and in your polling loop ... 
synchronized(event) { 

    while(!stop) { 

     // ... do JDBC access ... 
     try { 

      // Wait 30 seconds, but break out as soon as the event is fired. 
      event.wait(30000); 
     } 

     catch(InterruptedException e) { 

      // Log a message and exit. Never ignore interrupted exception. 
      break; 
     } 
    } 
} 

Hoặc một cái gì đó như thế.

0

Bạn có thể đặt trường thành một giá trị phức hợp bao gồm (khái niệm) một ID tiến trình và dấu thời gian. [Tốt hơn, hãy sử dụng hai hoặc nhiều trường.] Bắt đầu một chuỗi trong quá trình sở hữu quyền truy cập vào trường và có vòng lặp, ngủ và cập nhật dấu thời gian. Sau đó, một quá trình bỏ phiếu đang chờ quyền truy cập vào trường có thể quan sát rằng dấu thời gian không được cập nhật trong một khoảng thời gian T (lớn hơn nhiều so với khoảng thời gian của vòng lặp cập nhật) và giả định rằng quá trình sở hữu trước đó đã chết .

Nhưng điều này vẫn dễ bị thất bại.

Trong các ngôn ngữ khác, tôi luôn cố gắng sử dụng các cuộc gọi flock() để đồng bộ hóa trên một tệp. Không chắc tương đương Java là gì. Nhận đồng thời thực nếu bạn có thể có thể.

0

Tôi ngạc nhiên không ai đề cập đến cơ chế ngắt được triển khai trong Java. Nó được coi là một giải pháp cho vấn đề ngăn chặn một sợi. Tất cả các giải pháp khác có ít nhất một lỗ hổng, đó là lý do tại sao cơ chế này là cần thiết để được thực hiện trong thư viện đồng thời Java.

Bạn có thể dừng một chuỗi bằng cách gửi một thông báo ngắt(), nhưng có những cách khác mà các luồng bị gián đoạn. Khi điều này xảy ra một InterruptedException được ném. Đó là lý do tại sao bạn phải xử lý nó khi gọi sleep() chẳng hạn. Đó là nơi bạn có thể làm sạch và kết thúc một cách duyên dáng, như đóng kết nối cơ sở dữ liệu.

0

Tôi nghĩ bạn nên thăm dò ý kiến ​​với timertask thay thế.

Máy tính của tôi đang chạy vòng lặp while 1075566 lần trong 10 giây. Thats 107557 lần trong một giây.

Tần suất thật sự cần thiết để thăm dò ý kiến? TimerTask chạy nhanh nhất 1000 lần trong 1 giây. Bạn cung cấp cho nó một tham số trong int (miliseconds) làm tham số. Nếu bạn đang có nội dung với điều đó - điều đó có nghĩa là bạn căng thẳng cpu của bạn 108 lần ít hơn với nhiệm vụ đó.

Nếu bạn hài lòng với việc bỏ phiếu một lần mỗi giây là (108 * 1000). 108 000 lần ít căng thẳng hơn. Điều đó cũng có nghĩa là bạn có thể kiểm tra 108 000 giá trị với cùng một cpu căng thẳng mà bạn đã có với một trong khi vòng lặp của bạn - beause bạn không chỉ định cpu của bạn để kiểm tra thường xuyên. Hãy nhớ rằng cpu có một chu kỳ đồng hồ. Của tôi là 3 600 000 000 hertz (chu kỳ mỗi giây).

Nếu mục tiêu của bạn là cập nhật cho người dùng - bạn có thể chạy kiểm tra mỗi khi người dùng đăng nhập (hoặc tự cho phép anh ấy yêu cầu cập nhật) - điều đó thực tế không làm căng thẳng CPU.

Bạn cũng có thể sử dụng thread.sleep(miliseconds); để giảm căng thẳng cho chuỗi chỉ định của bạn (vì nó sẽ không được thăm dò thường xuyên) ở nơi bạn làm.

0

Java9 có một "tiềm năng" câu trả lời cho điều này: Thread.onSpinWait():

Chỉ ra rằng người gọi là trong giây lát không thể tiến bộ, cho đến khi sự xuất hiện của một hoặc nhiều hành động trên một phần của các hoạt động khác. Bằng cách gọi phương thức này trong mỗi lần lặp của một cấu trúc vòng lặp chờ đợi, chuỗi gọi cho biết thời gian chạy mà nó đang bận. Thời gian chạy có thể có hành động để cải thiện hiệu suất của việc gọi các cấu trúc vòng lặp chờ đợi.

Xem JEP 285 để biết thêm chi tiết.