2012-07-16 36 views
26

Tôi biết Thread.sleep() có thể làm cho chuỗi java bị treo trong một thời gian, như một số mili giây và một số nano giây nhất định. Nhưng vấn đề là việc gọi hàm này cũng gây ra chi phí.Làm cách nào để tạm dừng một chuỗi java trong một khoảng thời gian ngắn, chẳng hạn như 100 nano giây?

Ví dụ: nếu tôi muốn một chuỗi bị treo trong 100 nano giây và tôi gọi Thread.sleep (0, 100). Toàn bộ chi phí cho quá trình này là invocation_cost + 100 nanosceonds, có thể lớn hơn nhiều so với những gì tôi muốn. Làm thế nào tôi có thể tránh được vấn đề này, và đạt được mục đích của tôi?

Lý do tôi cần điều này là tôi muốn làm mô phỏng ngoại tuyến. Tôi đã lược tả thời gian thực hiện một nhiệm vụ; Bây giờ tôi muốn mô phỏng thời gian thực hiện này bằng cách đình chỉ một chủ đề trong cùng một khoảng thời gian.

Cảm ơn!

+8

Bạn có lý do cụ thể khiến bạn muốn thực hiện việc này không? Nếu vậy, nó có thể được giải quyết theo một cách khác ... –

+0

Đây là một yêu cầu bất thường. Có vẻ như bạn cần [chiến lược phản hồi] (http://en.wikipedia.org/wiki/Exponential_backoff) hoặc tương tự. – Bohemian

+1

@gt FYI, thật khó chịu khi đăng câu hỏi lên stackoverflow và có câu trả lời cho câu hỏi của bạn thay vì cung cấp câu trả lời. Có nhiều lý do hợp lệ để muốn làm điều này đã phát sinh trong các dự án trong những năm qua. Một lý do thực tế là để duy trì hành vi thời gian thực trong các ứng dụng ghi lại âm thanh từ phần cứng, vì phần cứng có thể hoạt động không nhất quán hoặc bạn có thể mô phỏng hành vi phần cứng cho mục đích thử nghiệm. – EntangledLoops

Trả lời

17

Độ chi tiết của giấc ngủ thường bị ràng buộc bởi khoảng thời gian ngắt của trình lên lịch. Trong Linux, thời gian gián đoạn này thường là 1ms trong nhân gần đây. Trong Windows, thời gian ngắt của scheduler là bình thường khoảng 10 hoặc 15 mili giây

Nếu tôi có để ngăn chặn chủ đề trong thời gian ít hơn thế này, tôi thường sử dụng một chờ đợi bận rộn

EDIT: Tôi nghi ngờ bạn sẽ nhận được kết quả tốt nhất trên jrockit + solaris. Những con số trên một cửa sổ hộp là khủng khiếp.

@Test 
public void testWait(){ 
    final long INTERVAL = 100; 
    long start = System.nanoTime(); 
    long end=0; 
    do{ 
     end = System.nanoTime(); 
    }while(start + INTERVAL >= end); 
    System.out.println(end - start); 
} 
+1

Cảm ơn. Nếu sử dụng chờ đợi bận rộn, làm thế nào bạn có thể kiểm soát độ dài chờ đợi? như 100 nano giây. – JackWM

+1

Nếu **> = ** được ** <= **? – JackWM

+0

xin lỗi tôi đã sai – JackWM

1

Một vấn đề nữa với Thread.sleep() là nó không được đảm bảo để đánh thức sau thời gian được chỉ định. Một chủ đề ngủ là guarenteed ngủ cho nano/micro giây quy định nhưng không guarenteed để thức dậy ngay lập tức sau đó. Vì bạn đang nói interms của nano giây, bạn có thể muốn thử Object.wait(long, int).

Tôi đã khá nhất quán với thứ tự 10s của nano giây với phương pháp trên.

+2

Trong cả hai trường hợp, khi bạn gọi 'Thread.sleep()' và 'Object.wait()' thì chuỗi đang chạy đi vào chế độ 'TIMED_WAITING'. Điều này ngụ ý rằng thread từ bỏ CPU. Trong cả hai trường hợp, khi thời gian chờ kết thúc, CPU sẽ, rất có thể là bận rộn làm một cái gì đó khác. Không có gì đảm bảo rằng thread waking sẽ nhận được CPU cùng một lúc, và thậm chí nếu nó đã làm, nó vẫn phải trả thời gian chuyển ngữ cảnh, theo câu hỏi, đây là những gì người điều tra muốn tránh. –

+0

Hơn nữa, trong mã của 'Object.wait (timeout, nanos)' bạn có thể thấy rằng nếu 'nanos> 0' nó chỉ tăng' timeout' lên 1. – awfun

1

Thực hiện một sự chờ đợi bận rộn, (ví dụ: có chu kỳ vòng lặp while qua rất nhiều số không làm gì cả). Một khởi đầu của chương trình của bạn, bạn có thể thời gian của nó đã mất nó thực hiện chờ đợi bận rộn này và tăng hoặc giảm nó để đến 5 nano giây

Tôi đã tìm thấy object.wait được lông với tần số này cũng lưu ý rằng Do đó, tại sao bạn nên có một bước hiệu chuẩn khi bắt đầu chương trình

12

Để mô phỏng, tôi sẽ không cố gắng mô phỏng theo thời gian thực vì điều này không cho bạn kết quả tái sản xuất. tức là bạn không thể kiểm tra mô phỏng của mình.

Thay vào đó, tôi sẽ sử dụng dữ liệu được điều khiển, đồng hồ mô phỏng và chạy mọi thứ nhanh nhất có thể. Điều này mang lại cho bạn kết quả có thể tái tạo và cho phép bạn mô phỏng nhanh hơn thời gian thực (ví dụ: 2x đến 100x nhanh hơn)


Nghi ngờ một chuỗi mất khoảng 10 giây. Không có điểm cố gắng đình chỉ một sợi cho thời gian ít hơn mà điều này.

Để chờ đợi trong một thời gian ngắn, bạn có thể thử.

long start = System.nanotime(); 
while(start + delay >= System.nanoTime()); 

Lưu ý: như @EugeneBeresovsky ý kiến, sau khi máy tính của bạn đã được chạy trong 292 năm này có thể tràn, do đó bạn có thể chọn để viết những dòng này như

while(System.nanoTime() - start < delay); 

này sẽ tinh cho sự chậm trễ của ít hơn 292 thay vào đó là năm. Bạn có thể sử dụng System.currentTimeMillis() để trì hoãn lâu hơn nữa.

Tuy nhiên, ngay cả điều này cũng không đáng tin cậy vì System.nanoTime() có thể mất đến 300 ns trên Centos 5.x nên gọi nó hai lần sẽ mất nhiều thời gian hơn 100 ns. Ngoài ra nhiều hệ điều hành chỉ có độ phân giải 1000 ns (1 micro giây) nên vòng lặp này sẽ đợi tới 1 micro giây, bất kể độ trễ bạn đang tìm kiếm.

Thay vào đó, những gì bạn có thể làm là bận rộn chờ đợi trong một vòng lặp ngắn không được tối ưu hóa.

Đối với sự chậm trễ 100 ns, tôi nghi ngờ sẽ tốt hơn khi bận chờ đợi trên bất cứ điều gì bạn đang chờ đợi thay vì tạo một vòng lặp bận rộn riêng biệt.

+0

Bài tốt. Tôi đã chỉnh sửa < to > = để sửa mã (xem lại, ">" thậm chí còn tốt hơn). Tôi đã thực hiện một vài thay đổi tầm thường khác để đạt được bản chỉnh sửa ký tự tối thiểu là 6 (argh). Cảm ơn. –

+0

Điều kiện trong khi của bạn bị lỗi tràn số nguyên. Bạn phải so sánh sự khác biệt của hai kết quả nanoTime() so với một số giá trị tuyệt đối, như được thực hiện, ví dụ: bởi @EntangledLoops, thay vì so sánh hai giá trị nanoTime tuyệt đối với nhau. –

+0

@EugeneBeresovsky Giá trị dài sẽ tràn sau khi máy của bạn đã chạy được 292 năm ... Tôi sẽ cập nhật câu trả lời của mình. –

2
public static void busySleep(long nanos) 
{ 
    long elapsed; 
    final long startTime = System.nanoTime(); 
    do { 
    elapsed = System.nanoTime() - startTime; 
    } while (elapsed < nanos); 
} 
Các vấn đề liên quan