2009-03-19 21 views
31

Chức năng sau đây được thực hiện trong chủ đề riêng của mình:Luồng trong Java: Làm thế nào để khóa một đối tượng?

private void doSendData() 
{ 
    try { 

      //writeToFile(); // just a temporary location of a call 
      InetAddress serverAddr = InetAddress.getByName(serverAddress); 
      serverAddr.wait(60000); 
      //Log.d("TCP", "C: Connecting..."); 
      Socket socket = new Socket(serverAddr, portNumber); 
      socket.setSoTimeout(3000); 

       try { 
       //Log.d("TCP", "C: Sending: '" + message + "'"); 
       PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())),true); 
       String message = packData(); 
       out.println(message); 
       Log.d("TCP", "C: Sent."); 
       Log.d("TCP", "C: Done."); 
       connectionAvailable = true; 

      } catch(Exception e) { 
       Log.e("TCP", "S: Error", e); 
       connectionAvailable = false; 

       } finally { 
        socket.close(); 
        announceNetworkAvailability(connectionAvailable); 
       } 

     } catch (Exception e) { 
       Log.e("TCP", "C: Error", e); 
       announceNetworkAvailability(connectionAvailable); 
     } 
} 

Khi thực hiện đạt các dòng serverAddr.wait(60000) nó ném một ngoại lệ:

java.lang.IllegalMonitorStateException: object not locked by thread before wait() 

Có ai biết làm thế nào để khóa một đối tượng hoặc một hàm trong để ngăn ngừa đồng thời? Tôi đã cố gắng thêm một đối tượng Lock:

private final Lock lock = new ReentrantLock(); 

và dòng

boolean locked = lock.tryLock(); 

vào đầu chức năng nhưng nó đã không làm việc.

+0

bạn muốn làm gì? WAIT không có ý nghĩa gì cả ... – ReneS

Trả lời

64

Để gọi wait() trên một đối tượng, bạn phải giữ khóa đồng bộ trên đối tượng đó (mặc dù khóa được thực sự phát hành trong khi thread đang chờ):

synchronized (serverAddr) { 
    serverAddr.wait(); 
} 

tôi phải thừa nhận rằng tại sao bạn đang muốn làm điều này baffles tôi trong trường hợp này ...

+0

Xin lỗi, chỉ cần rõ ràng: Tôi hiểu tại sao bạn phải lấy khóa trên vật thể trước khi chờ nó. Những gì tôi không hiểu là * logic * của những gì các poster ban đầu là thực sự cố gắng để làm ... !!! –

+1

Oh, sau đó bình luận của tôi là redacted :) –

+1

+1 cho "khóa thực sự được phát hành trong khi thread đang chờ đợi", đã giúp tôi khắc phục một vấn đề khác và tôi đã không nhận thức được rằng (có, mới đến java) – spirytus

1

Để tránh điều đó thông báo lỗi, sử dụng từ khóa synchronized:

synchronized(serverAddr){ 
    serverAddr.wait(60000); 
} 
11

Tôi luôn luôn rạn nứt khi tôi thấy loại mã này. Làm cho bạn một ưu và có một cái nhìn tại gói java.util.concurrent.

+0

cũng xem Câu hỏi của tôi. http://stackoverflow.com/q/31966790/4260932 –

1

Ở trên là chính xác. Bạn có thể sử dụng một khối mã được đồng bộ hóa. Hoặc bạn có thể tạo ra những gì họ gọi là một mutex. Một mutex thực sự có thể là đối tượng bất kỳ. Rất nhiều người chỉ sử dụng Object làm mutex. Sau đó, bạn có thể khóa trên mutex. Bất kỳ chủ đề nào muốn truy cập phải đợi chuỗi giữ macro để giải phóng nó.

Cũng có một đề xuất của Apocalisp. Tôi cũng khuyên bạn nên xem gói java.util.concurrent.

21

Có thể phương pháp bạn đang tìm kiếm là Thread.sleep(long)? Phương pháp này sẽ chờ (như ngừng hoạt động của luồng) trong thời gian được chỉ định bằng mili giây trước khi tiếp tục.

object.wait(long) (đó là những gì bạn đang sử dụng) thực hiện điều gì đó hoàn toàn khác. Nó đợi một đối tượng khác từ một luồng khác để thông báo cho nó (ví dụ: gửi cho nó một loại thông báo đánh thức), và sẽ đợi tối đa số mili giây được chỉ định. Với mã bạn đăng, tôi rất nghi ngờ đây là những gì bạn thực sự muốn.

Nếu Thread.sleep() không phải là những gì bạn muốn, thì bạn nên sử dụng khối được đồng bộ như được đề cập bởi các áp phích khác.

+0

plz có xem Câu hỏi của tôi http://stackoverflow.com/q/31966790/4260932 –

0

Nói chung khi bạn có chương trình đa luồng trong Java, bạn cần khóa biến được chia sẻ bằng cách sử dụng đồng bộ (từ khóa), sau đó chỉ trong một chuỗi có thể truy cập bộ nhớ dùng chung.

0

Mã bên dưới sẽ hoạt động.

 private final ReentrantLock lock = new ReentrantLock(); 

    lock.lock(); // block until condition holds 
    try { 
     serverAddr.wait(60000); 
    } finally { 
     lock.unlock() 
    } 
    } 

Tham khảo tài liệu này page để biết thêm chi tiết.

public void lock() 

Dành được khóa.

Mua khóa nếu nó không được giữ bởi một sợi khác và trả về ngay lập tức, đặt số lần giữ khóa thành một.

Nếu chủ đề hiện tại đã giữ khóa thì số lượng giữ được tăng lên một và phương thức trả về ngay lập tức.

Nếu khóa được tổ chức bởi thread khác sau đó xử lí hiện tại trở nên tàn tật cho các mục đích đề lập kế hoạch và nằm im cho đến khi khóa đã được mua lại, lúc đó số lượng khóa giữ được thiết lập để một

Tham khảo này SE câu hỏi để biết những ưu điểm của lock qua synchronization:

Synchronization vs Lock

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