lịch trìnhAtFixedRate so với lịch trìnhWithFixedDelay


117

Sự khác biệt chính giữa là gì scheduleAtFixedRatescheduleWithFixedDelayphương pháp ScheduledExecutorService ?

scheduler.scheduleAtFixedRate(new Runnable() {
    @Override
    public void run() {
        System.out.println("scheduleAtFixedRate:    " + new Date());
    }
}, 1, 3L , SECONDS);

scheduler.scheduleWithFixedDelay(new Runnable() {
    @Override
    public void run() {
        System.out.println("scheduleWithFixedDelay: " + new Date());
    }
}, 1, 3L , SECONDS);

chúng in chính xác cùng một lúc, dường như chúng được thực thi chính xác trong cùng một khoảng thời gian.

Câu trả lời:


206

Hãy thử thêm một Thread.sleep(1000);cuộc gọi trong run()phương thức của bạn ... Về cơ bản, đó là sự khác biệt giữa việc lập lịch trình một cái gì đó dựa trên thời điểm thực thi trước đó kết thúc và khi nó bắt đầu (một cách hợp lý) .

Ví dụ: giả sử tôi lên lịch báo thức kêu với tốc độ cố định là một lần một giờ và mỗi khi báo thức kêu , tôi sẽ uống một tách cà phê, mất 10 phút. Giả sử điều đó bắt đầu vào lúc nửa đêm, tôi sẽ có:

00:00: Start making coffee
00:10: Finish making coffee
01:00: Start making coffee
01:10: Finish making coffee
02:00: Start making coffee
02:10: Finish making coffee

Nếu tôi lên lịch với độ trễ cố định là một giờ, tôi sẽ có:

00:00: Start making coffee
00:10: Finish making coffee
01:10: Start making coffee
01:20: Finish making coffee
02:20: Start making coffee
02:30: Finish making coffee

Bạn muốn cái nào tùy thuộc vào nhiệm vụ của bạn.


18
Điều gì xảy ra trong kịch bản fixedRate nếu mất hơn một giờ để pha cà phê?
Brett VanderVeen

5
@BrettVanderVeen: Tôi tin rằng điều đó phụ thuộc vào người thực thi được đề cập. Nó sẽ được lên lịch đúng giờ - nhưng liệu điều đó có thực thi hay không phụ thuộc vào việc có một luồng có sẵn cho trình thực thi đó hay không. Tôi khuyên bạn nên thử nghiệm để xem điều này hoạt động như thế nào trong các trường hợp khác nhau.
Jon Skeet

8
@BrettVanderVeen Từ tài liệu , "Nếu bất kỳ quá trình thực thi nào của tác vụ này kéo dài hơn thời gian của nó, thì các lần thực thi tiếp theo có thể bắt đầu muộn, nhưng sẽ không thực thi đồng thời." Nói cách khác, một triển khai tuân thủ sẽ không cho phép cái tiếp theo thực thi cho đến khi cái trước đó kết thúc.
M. Justin

Bạn có thể cung cấp mã làm việc cho đầu ra được hiển thị (cà phê) cho một người mới làm quen như tôi không?
MuneshSingh

@MuneshSingh: Không phải trong câu hỏi này, câu hỏi này đang yêu cầu giải thích sự khác biệt giữa lập lịch với tốc độ cố định và lập lịch với độ trễ cố định. Tuy nhiên, bạn sẽ không tự thực hiện điều này - bạn sẽ sử dụng các trình thực thi tích hợp sẵn.
Jon Skeet

57

Hình dung chuỗi thời gian của scheduleAtFixedRatephương pháp gọi . Các lần thực thi tiếp theo sẽ bắt đầu ngay lập tức nếu lần cuối cùng mất nhiều thời gian hơn. Nếu không, nó sẽ bắt đầu sau khoảng thời gian.

chuỗi thời gian của phương thức lịch trình lời gọiAtFixedRate

Chuỗi thời gian của scheduleWithFixedDelayphương thức gọi . Lần thực hiện tiếp theo sẽ bắt đầu sau thời gian trì hoãn từ khi kết thúc một lần thực hiện đến khi bắt đầu lần thực hiện tiếp theo, bất kể thời gian thực hiện của nó là bao nhiêu

chuỗi thời gian của lịch trình gọi phương thứcWithFixedDelay

Hy vọng có thể giúp bạn


Tôi không thể hiểu từ "bổ sung" được đề cập trong biểu đồ chuỗi thời gian SchedAtFixedRate.
MuneshSingh

1
@MuneshSingh Nó có nghĩa là để chỉ ra rằng thời gian thực hiện của tác vụ lâu hơn so với lịch trình, vì vậy nó mất thêm thời gian và lần thực thi tiếp theo bắt đầu ngay lập tức.
Viorel

@Viorel cảm ơn đã làm rõ. Điều đó có nghĩa là "khoảng thời gian" không chính xác là khoảng thời gian trễ cố định giữa hai lần thực hiện liên tiếp.
MuneshSingh

1
@MuneshSingh Khoảng thời gian được cố định, nhưng nó sẽ không dừng tác vụ hiện tại khi nó vượt qua nó, đơn giản là sẽ không có độ trễ giữa lần chạy này và lần tiếp theo. Nếu bạn muốn tạo "thời gian chờ", bạn có thể muốn giữ lại Tương lai và hủy nó trong một trình thực thi khác. Nói một cách đơn giản, nó cho biết hãy bắt đầu lần thực hiện đầu tiên và lần thực hiện tiếp theo càng sớm càng tốt sau khi thời gian "giai đoạn" trôi qua .
Viorel

4

Các scheduleAtFixedRate()phương pháp tạo ra một nhiệm vụ mới và nộp cho người thi hành mỗi kỳ, bất kể có hay không phải là nhiệm vụ trước đã hoàn thành .

Mặt khác, scheduleWithFixedDelay()phương thức tạo một tác vụ mới sau khi tác vụ trước đó đã kết thúc .


Bạn đã viết hai lần scheduleAtFixedRate:)
Vlad

3

Nếu bạn đọc Java Doc thì sẽ rõ hơn

SchedisedFuture historyAtFixedRate (Lệnh Runnable, Long initialDelay, long period, TimeUnit unit) Tạo và thực hiện một hành động định kỳ được kích hoạt đầu tiên sau độ trễ ban đầu nhất định, sau đó với khoảng thời gian nhất định; nghĩa là các quá trình thực thi sẽ bắt đầu sau thời gian ban đầu (InitialDelay) rồi đến thời gian ban đầu + thời gian, sau đó dấu chấm khởi tạo + 2 *, v.v.

Lịch trình SchedisedFutureWithFixedDelay (Lệnh Runnable, Long InitialDelay, delay lâu, đơn vị TimeUnit) Tạo và thực hiện một hành động định kỳ được kích hoạt đầu tiên sau độ trễ ban đầu nhất định và sau đó với độ trễ nhất định giữa việc kết thúc một lần thực hiện và bắt đầu hành động tiếp theo.


1

Có một lỗi trong ScheduleAtFixedRate nếu luồng đầu tiên mất quá nhiều thời gian và không kết thúc trong khoảng thời gian nhất định thì luồng quan trọng thứ hai sẽ không bắt đầu sau khi nhiệm vụ đầu tiên được hoàn thiện và sẽ không bắt đầu ngay trong khi luồng đầu tiên đã thêm nhiệm vụ và thời lượng gievn của chúng đã được trôi qua. JVM Sẽ quyết định khi nào nhiệm vụ tiếp theo sẽ được thực thi.

Tôi nghĩ rằng điều đó sẽ giúp bạn chọn phương pháp Becuase vì điều này tôi có một vấn đề lớn


1
Gì? JVM sẽ quyết định? Điều đó thậm chí có nghĩa là gì? Đúng là các Runnable sẽ không được thực hiện đồng thời với chính nó như là mỗi tài liệu, nhưng nó quyết định của chấp hành viên, có thể tùy chỉnh HOẶC tiêu chuẩn ScheduledThreadPoolExecutor(và sau này cũng đã xác định hành vi)
Ordous

Không, tôi đã tìm thấy vấn đề tương tự trong ứng dụng của mình, nơi tôi đã đưa ra khoảng thời gian 15 phút và tác vụ đầu tiên không hoàn thành trong 15 phút và mất 15,30 giây vì vậy tác vụ thứ hai không bắt đầu ngay lập tức, nó bắt đầu sau 5 phút và một thời gian sau 8 phút và tôi không biết liệu chúng ta có thể kiểm soát hành vi này hay không vì đây không phải là hành vi chuẩn.
user1047873,

Điều đó nghe giống như xếp hàng nhiệm vụ sách giáo khoa.
Bình thường

Có, nó chỉ có nghĩa là tất cả các luồng trong trình thực thi của bạn đã bận làm một việc gì đó và nhiệm vụ của bạn được đưa vào một hàng đợi những việc cần làm. ( LƯU Ý bạn cần xác nhận điều này bằng cách xem hàng đợi đã nói hoặc xem các luồng thực thi đang làm gì). Cách bạn kiểm soát điều này phụ thuộc vào loại người thực thi bạn có. Bạn có thể muốn tạo một trình thực thi 1 luồng riêng biệt chỉ cho tác vụ cụ thể này, sau đó nó sẽ không chờ đợi bất cứ điều gì. Hoặc cung cấp cho người thực thi hiện tại của bạn nhiều chủ đề hơn. Hoặc thay đổi chiến lược của nó.
Bình thường

0

Hãy viết một chương trình đơn giản:

import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit

var time = 0L
var start = System.currentTimeMillis()
val executor = Executors.newScheduledThreadPool(1)
executor.scheduleWithFixedDelay({
    if (time >= 12_000L) {
        executor.shutdown()
    } else {
        Thread.sleep(2000L)
        val now = System.currentTimeMillis()
        time += now - start
        System.out.println("Total $time delay ${now - start}\n")
        start = now
    }
}, 0L, 1000L, TimeUnit.MILLISECONDS)

Và xem kết quả:

| scheduleWithFixedDelay |   scheduleAtFixedRate  |
|:----------------------:|:----------------------:|
| Total 2001 delay 2001  | Total 2003 delay 2003  |
| Total 5002 delay 3001  | Total 4004 delay 2001  |
| Total 8003 delay 3001  | Total 6004 delay 2000  |
| Total 11003 delay 3000 | Total 8004 delay 2000  |
| Total 14003 delay 3000 | Total 10005 delay 2001 |
|          ---           | Total 12005 delay 2000 |

LƯU Ý thời gian thực hiện lớn hơn thời gian chờ đợi

ScheduleWithFixedDelay giữ
lịch trình trì hoãnAtFixedRate loại bỏ độ trễ


-1
scheduledExecutorService.scheduleAtFixedRate(() -> {
        System.out.println("runnable start"); try { Thread.sleep(5000);  System.out.println("runnable end");} catch
     (InterruptedException e) { // TODO Auto-generated catch block
      e.printStackTrace(); }}, 2, 7, TimeUnit.SECONDS);



     scheduledExecutorService.scheduleWithFixedDelay(() -> {
     System.out.println("runnable start"); try { Thread.sleep(5000); System.out.println("runnable end");} catch
     (InterruptedException e) { // TODO Auto-generated catch block
     e.printStackTrace(); } }, 2, 7, TimeUnit.SECONDS);

Chỉ cần thực hiện nó, và bạn sẽ biết sự khác biệt. Cảm ơn bạn


1
Vui lòng giải thích cách mã giải quyết vấn đề của OP. :)
Yash
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.