2010-08-21 31 views
42

Trong NetBeans, có một gợi ý mới cho biết: Thread.sleep được gọi trong vòng lặp.NetBeans/Java/Gợi ý mới: Thread.sleep được gọi trong vòng lặp

Câu hỏi 1: Làm thế nào khi nào có thể xảy ra sự cố khi ngủ trong vòng lặp?

Câu hỏi 2: Nếu đó là vấn đề, tôi nên làm gì?

CẬP NHẬT: Câu hỏi 3: Dưới đây là một số mã. Nói với tôi trong trường hợp này nếu tôi nên sử dụng cái gì khác thay vì Thread.Sleep trong một vòng lặp. Trong ngắn hạn, điều này được sử dụng bởi một máy chủ mà lắng nghe các kết nối TCP khách hàng. Giấc ngủ được sử dụng ở đây trong trường hợp đạt đến số lượng phiên tối đa với khách hàng. Trong tình huống này, tôi muốn ứng dụng đợi cho đến khi phiên miễn phí khả dụng.

public class SessionManager { 
    private static final int DEFAULT_PORT = 7500; 
    private static final int SLEEP_TIME = 200; 
    private final DatabaseManager database = new DatabaseManager(); 
    private final ServerSocket serverSocket = new ServerSocket(DEFAULT_PORT); 

public SessionManager() throws IOException, SQLException 
{ 
} 

public void listen() 
{ 
while (true) 
    if (Session.getSessionCount() < Session.getMaxSessionCount()) 
     try 
     { 
      new Thread(new Session(database, serverSocket.accept())).start(); 
     } 
     catch (IOException ex) { ex.printStackTrace(); } 
    else 
     try 
     { 
      Thread.sleep(SLEEP_TIME); 
     } 
     catch (InterruptedException ex) { ex.printStackTrace(); } 
} 

public static void main(String[] args) throws IOException, SQLException 
{ 
new SessionManager().listen(); 
} 
} 

Trả lời

19

Gọi ngủ trong vòng lặp thường dẫn đến hiệu suất kém. Ví dụ:

while (true) { 
    if (stream.available() > 0) { 
     // read input 
    } 
    sleep(MILLISECONDS); 
} 

Nếu MILLISECONDS quá lớn, thì mã này sẽ mất nhiều thời gian để nhận ra rằng đầu vào có sẵn.

Nếu MILLISECONDS quá nhỏ, thì mã này sẽ lãng phí rất nhiều tài nguyên hệ thống kiểm tra đầu vào chưa đến.

Các ứng dụng khác của sleep trong vòng lặp thường có vấn đề. Thường có cách tốt hơn.

Nếu đó là vấn đề, tôi nên làm gì?

Đăng mã và có thể chúng tôi có thể cung cấp cho bạn câu trả lời hợp lý.

EDIT

IMO, một cách tốt hơn để giải quyết vấn đề là sử dụng một ThreadPoolExecutor.

Something như thế này:

public void listen() { 
    BlockingQueue queue = new SynchronousQueue(); 
    ThreadPoolExecutor executor = new ThreadPoolExecutor(
      1, Session.getMaxSessionCount(), 100, TimeUnit.SECONDS, queue); 
    while (true) { 
     try { 
      queue.submit(new Session(database, serverSocket.accept())); 
     } catch (IOException ex) { 
      ex.printStackTrace(); 
     } 
    } 
} 

này cấu hình người thi hành để phù hợp với cách mã của bạn hiện đang hoạt động. Có một số cách khác bạn có thể làm; xem liên kết javadoc ở trên.

+0

Làm thế nào về một java.util.Timer và TimerTask định kỳ? – Core

+0

@Core - nó phụ thuộc vào cách bạn sử dụng nó. Nếu bạn chỉ sử dụng nó để thực hiện tương đương với 'sleep()', bạn có cùng các vấn đề như sử dụng 'sleep()'. –

+0

nếu chúng ta đang sử dụng managedexecutorservice thì sao? – wib

2

Làm thế nào khi nào có thể xảy ra sự cố khi ngủ trong vòng lặp?
Mọi người đôi khi sử dụng nó thay cho các phương pháp đồng bộ hóa thích hợp (như chờ/thông báo).

Nếu đó là vấn đề, tôi nên làm gì?
Phụ thuộc vào những gì bạn đang làm. Mặc dù điều đó khiến tôi tưởng tượng ra tình huống khi làm điều này là cách tiếp cận tốt nhất, tôi đoán điều đó cũng có thể xảy ra.

Bạn có thể kiểm tra về chủ đề này.

+0

Mọi người cũng thỉnh thoảng sử dụng nó trong vòng đọc kết hợp với kiểm tra có sẵn(), khi họ chỉ cần được ngăn chặn trong đọc thay vì thời gian và không gian lãng phí. – EJP

+0

Một cách sử dụng là trình dọn dẹp thư mục, xóa các tệp cũ hơn một khoảng thời gian nhất định. Sau lần chạy đầu tiên, chúng tôi biết đó là tệp cũ nhất và chính xác khoảng thời gian cho đến khi nó trở thành "quá cũ", vì vậy chúng tôi có thể ngủ trong khoảng thời gian đó. – Jesse

+0

@Jesse - trình quản lý nhóm theo lịch trình có thể sẽ tốt hơn cho điều đó. –

3

Như những người khác đã nói nó phụ thuộc vào cách sử dụng.Sử dụng hợp pháp sẽ là một chương trình được thiết kế để thực hiện điều gì đó sau mỗi 10 giây (nhưng không quá quan trọng đến mức cần có thời gian chính xác). Chúng tôi có rất nhiều "ứng dụng tiện ích" này nhập dữ liệu và các tác vụ khác cứ sau vài phút. Đây là một cách dễ dàng để thực hiện các tác vụ này và chúng tôi thường sẽ đặt khoảng thời gian ngủ là rất thấp và sử dụng bộ đếm để chương trình luôn đáp ứng và có thể thoát dễ dàng.

int count = 0; 
while (true) { 

    try { 
     // Wait for 1 second. 
     Thread.sleep(1000); 
    } 
    catch (InterruptedException ex) {} 

    // Check to see if the program should exit due to other conditions. 
    if (shouldExit()) 
     break; 

    // Is 10 seconds up yet? If not, just loop back around. 
    count++; 
    if (count < 10) continue; 

    // 10 seconds is up. Reset the counter and do something important. 
    count = 0; 
    this.doSomething(); 
} 
+1

Sử dụng trình thực thi hồ bơi theo lịch trình thay vì sẽ tốt hơn về mặt kỹ thuật trong hầu hết các trường hợp, nhưng điều đó đôi khi quá nhiều khi bạn chỉ đang lập trình một cái gì đó nhanh chóng và bẩn. – mjaggard

+0

@mjaggard cho phép nói rằng tôi hiện đang có một chuỗi với một vòng lặp với một giấc ngủ bên trong. Nó đang làm nhiệm vụ vệ sinh chẳng hạn như thanh lọc dữ liệu cũ không liên quan nữa. Việc sử dụng trình quản lý nhóm luồng được lên lịch sẽ thêm độ phức tạp không cần thiết vào mã, so với chỉ có một chuỗi dài, chủ yếu là nhàn rỗi. Bối cảnh chuyển đổi hình phạt là không đáng kể đối với một sợi dài sống/nhàn rỗi đang ngủ. Những gì hiện một hồ bơi theo lịch trình chủ đề thực sự mua bạn, khác hơn là loại bỏ các "nó không phải là một thực hành tốt" cảnh báo? – ruckc

+2

Bạn đã viết mã cho mỗi? Tôi nghi ngờ rằng các phiên bản thực thi hồ bơi dự kiến ​​thread có thể thực sự ngắn hơn, dễ đọc hơn và hiệu quả rất giống nhau. – mjaggard

1

Tôi nghĩ rằng tôi bắt gặp một cách sử dụng hoàn toàn hợp pháp phương pháp sleep() trong vòng lặp.

Chúng tôi có kết nối một chiều giữa máy chủ và ứng dụng khách. Vì vậy, khi khách hàng muốn đạt được truyền thông không đồng bộ với máy chủ, anh ta gửi tin nhắn đến máy chủ và hơn bình chọn định kỳ cho một số phản hồi từ máy chủ. Cần có khoảng thời gian chờ.

Response resp = null; 
for (int i = 0; i < POLL_REPEAT && resp == null; i++) { 
    try { 
     Thread.sleep(POLL_INTERVAL); 
    } catch (InterruptedException ie) { 
    } 
    resp = server.getResponse(workflowId); 
} 

POLL_REPEAT * POLL_INTERVAL ~ khoảng TIMEOUT

+1

Một giải pháp tốt hơn nếu có thể với API của bạn sẽ là sử dụng một phương pháp IO chặn, đợi cho đến khi dữ liệu mới có sẵn. – Vitruvius

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