Timer & TimerTask so với Thread + sleep trong Java


102

Tôi tìm thấy những câu hỏi tương tự được hỏi ở đây nhưng không có câu trả lời cho sự hài lòng của tôi. Vì vậy, nói lại câu hỏi một lần nữa-

Tôi có một nhiệm vụ cần được thực hiện theo định kỳ (giả sử khoảng thời gian 1 phút). Lợi thế của việc sử dụng Timertask & Timer để làm điều này thay vì tạo một luồng mới có vòng lặp vô hạn với chế độ ngủ là gì?

Đoạn mã sử dụng timertask-

TimerTask uploadCheckerTimerTask = new TimerTask(){

 public void run() {
  NewUploadServer.getInstance().checkAndUploadFiles();
 }
};

Timer uploadCheckerTimer = new Timer(true);
uploadCheckerTimer.scheduleAtFixedRate(uploadCheckerTimerTask, 0, 60 * 1000);

Đoạn mã sử dụng Chủ đề và giấc ngủ-

Thread t = new Thread(){
 public void run() {
  while(true) {
   NewUploadServer.getInstance().checkAndUploadFiles();
   Thread.sleep(60 * 1000);
  }
 }
};
t.start();

Tôi thực sự không phải lo lắng nếu tôi bỏ lỡ các chu kỳ nhất định nếu việc thực thi logic mất nhiều hơn khoảng thời gian.

Hãy bình luận về điều này ..

Cập nhật:
Gần đây tôi đã tìm thấy một sự khác biệt khác giữa việc sử dụng Timer so với Thread.sleep (). Giả sử giờ hệ thống hiện tại là 11:00 sáng. Nếu chúng tôi lùi thời gian hệ thống về 10:00 AM vì lý do nào đó, Bộ hẹn giờ sẽ NGỪNG thực thi tác vụ cho đến khi nó đạt đến 11:00 sáng, trong khi phương thức Thread.sleep () sẽ tiếp tục thực hiện tác vụ mà không gặp trở ngại. Đây có thể là người đưa ra quyết định chính trong việc quyết định sử dụng cái gì giữa hai cái này.


21
Điểm thứ tự: Timer và TimerTask đã lỗi thời và đã được thay thế bằng ExecutorService, mặc dù quan điểm của bạn vẫn còn nguyên.
skaffman 21/09/09

Cảm ơn vì mẹo này, tôi quyết định sử dụng ExecutorService :)
Keshav 21/09/09

Cảm ơn tất cả các bạn cho câu trả lời, chắc chắn đã cho tôi hiểu biết thêm!
Keshav 21/09/09

6
Bộ hẹn giờ không lỗi thời và được ưu tiên khi chỉ cần một luồng duy nhất. ( java.sun.com/javase/6/docs/api/java/util/Timer.html )
Justin

2
Timer và TimerTask vẫn hữu ích trong môi trường JME nơi ExecutorService không tồn tại (kể từ khi dựa trên JME Java 1.3 ...).
ス ー パ ー フ ァ ミ コ ン

Câu trả lời:


67

Ưu điểm của TimerTask là nó thể hiện ý định của bạn tốt hơn nhiều (tức là khả năng đọc mã) và nó đã được triển khai tính năng hủy ().

Lưu ý rằng nó có thể được viết ở dạng ngắn hơn cũng như ví dụ của riêng bạn:

Timer uploadCheckerTimer = new Timer(true);
uploadCheckerTimer.scheduleAtFixedRate(
    new TimerTask() {
      public void run() { NewUploadServer.getInstance().checkAndUploadFiles(); }
    }, 0, 60 * 1000);

nếu bộ đếm thời gian được sử dụng cho Hàng ngày, vào 2 thời gian cụ thể 9 giờ tối và 9 giờ sáng, ... thì làm thế nào để đưa ra các giá trị? trên đoạn mã trên ... @Zed?
gumuruh

12

Timer / TimerTask cũng tính đến thời gian thực hiện tác vụ của bạn, vì vậy nó sẽ chính xác hơn một chút. Và nó giải quyết tốt hơn các vấn đề đa luồng (chẳng hạn như tránh bế tắc, v.v.). Và tất nhiên sẽ tốt hơn nếu sử dụng mã tiêu chuẩn đã được kiểm tra kỹ lưỡng thay vì một số giải pháp tự chế.


5

Tôi không biết tại sao nhưng một chương trình mà tôi đang viết sử dụng Bộ đếm thời gian và kích thước đống của nó đang tăng liên tục, khi tôi thay đổi nó thành Chủ đề / vấn đề ngủ đã được giải quyết.


9
Bộ hẹn giờ tạo ra một hàng đợi các tác vụ được cập nhật liên tục. Khi Timer được thực hiện, nó có thể không được thu gom rác ngay lập tức. Vì vậy, việc tạo thêm Bộ hẹn giờ chỉ thêm nhiều đối tượng hơn vào đống. Thread.sleep () chỉ tạm dừng chuỗi, vì vậy chi phí bộ nhớ sẽ rất thấp.
Darryl Gerrow vào

4

Nếu luồng của bạn nhận được ngoại lệ và bị giết, đó là một vấn đề. Nhưng TimerTask sẽ lo việc đó. Nó sẽ chạy bất kể thất bại trong lần chạy trước đó.


4

Từ Timer tài liệu :

Java 5.0 đã giới thiệu gói java.util.concurrent và một trong những tiện ích đồng thời trong đó là SchedisedThreadPoolExecutor, là một nhóm luồng để thực thi lặp đi lặp lại các tác vụ với tốc độ hoặc độ trễ nhất định. Nó thực sự là một sự thay thế linh hoạt hơn cho sự kết hợp Timer / TimerTask, vì nó cho phép nhiều luồng dịch vụ, chấp nhận các đơn vị thời gian khác nhau và không yêu cầu phân lớp TimerTask (chỉ cần triển khai Runnable). Cấu hình SchedisedThreadPoolExecutor bằng một luồng làm cho nó tương đương với Timer.

Vì vậy Thích ScheduledThreadExecutorthay vì Timer:

  • Timersử dụng luồng nền duy nhất được sử dụng để thực thi tất cả các tác vụ của bộ định thời một cách tuần tự. Vì vậy, các tác vụ phải hoàn thành nhanh chóng nếu không nó sẽ làm trì hoãn việc thực hiện các tác vụ tiếp theo. Nhưng trong trường hợp của ScheduledThreadPoolExecutorchúng tôi, chúng tôi có thể cấu hình bất kỳ số lượng luồng nào và cũng có thể có toàn quyền kiểm soát bằng cách cung cấp ThreadFactory.
  • Timercó thể nhạy cảm với đồng hồ hệ thống vì nó sử dụng Object.wait(long)phương pháp. Nhưng ScheduledThreadPoolExecutorkhông phải.
  • Các ngoại lệ thời gian chạy được đưa ra trong TimerTask sẽ giết luồng cụ thể đó, do đó làm cho Timer chết khi chúng ta có thể xử lý điều đó ScheduledThreadPoolExecutorđể các tác vụ khác không bị ảnh hưởng.
  • Timercung cấp cancelphương thức để kết thúc bộ đếm thời gian và loại bỏ bất kỳ tác vụ đã lên lịch nào, tuy nhiên, nó không can thiệp vào tác vụ hiện đang thực thi và để nó hoàn thành. Nhưng nếu bộ đếm thời gian đang chạy dưới dạng luồng daemon thì dù chúng ta có hủy nó hay không, nó sẽ kết thúc ngay sau khi tất cả các luồng người dùng thực thi xong.

Hẹn giờ so với Thread.sleep

Bộ hẹn giờ sử dụng Object.waitvà nó khác vớiThread.sleep

  1. Một waitluồng đang chờ ( ) có thể được thông báo (sử dụng notify) bởi một luồng khác nhưng một luồng đang ngủ thì không thể được, nó chỉ có thể bị gián đoạn.
  2. Chờ đợi (và thông báo) phải xảy ra trong một khối được đồng bộ hóa trên đối tượng màn hình trong khi chế độ ngủ thì không.
  3. Trong khi ngủ không mở khóa, chờ đợi sẽ mở khóa cho đối tượng chờ được gọi.

thông tin rất hữu ích, Ngoài ra, việc sử dụng Thread.sleep trong một vòng lặp vô hạn có thể gây ra việc sử dụng CPU cao với độ trễ thời gian thấp.
Amir Fo

3

Có một lập luận quan trọng chống lại việc quản lý tác vụ này bằng cách sử dụng các luồng và sleepphương thức Java . Bạn đang sử dụng while(true)để ở vô thời hạn trong vòng lặp và ngủ đông chuỗi bằng cách chuyển sang chế độ ngủ. Điều gì NewUploadServer.getInstance().checkAndUploadFiles();sẽ xảy ra nếu chiếm một số tài nguyên đồng bộ. Các luồng khác sẽ không thể truy cập các tài nguyên này, tình trạng đói có thể xảy ra và có thể làm chậm toàn bộ ứng dụng của bạn. Những loại lỗi này rất khó chẩn đoán và bạn nên ngăn chặn sự tồn tại của chúng.

Aproach khác kích hoạt việc thực thi mã quan trọng với bạn, tức là NewUploadServer.getInstance().checkAndUploadFiles();bằng cách gọi run()phương thức của bạn TimerTasktrong khi cho phép các luồng khác sử dụng các tài nguyên trong khi đó.


16
Tôi không hiểu lập luận này. Cả hai lựa chọn khởi chạy cùng một phương thức từ một luồng, cả hai lựa chọn đều đang ngủ trong một luồng trong khi chúng chờ thực thi. Sẽ không có sự khác biệt nào về mức độ chết đói giữa hai sự lựa chọn.
satur9nine,

2

Tôi nghĩ rằng tôi hiểu vấn đề của bạn, tôi đang thấy một cái gì đó rất giống nhau. Tôi có bộ hẹn giờ lặp lại, một số cứ 30 phút một lần và một số hẹn giờ vài ngày một lần. Từ những gì tôi đọc và các nhận xét tôi thấy, có vẻ như bộ sưu tập rác sẽ không bao giờ chạy vì tất cả nhiệm vụ không bao giờ hoàn thành. Tôi nghĩ rằng bộ sưu tập rác sẽ chạy khi bộ hẹn giờ ở chế độ ngủ, nhưng tôi không nhìn thấy nó và theo tài liệu thì không.

Tôi nghĩ rằng việc sinh ra các chủ đề mới sẽ hoàn thành và cho phép thu gom rác.

Ai đó hãy chứng minh tôi sai, viết lại những gì tôi được thừa hưởng sẽ là một nỗi đau.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.