2010-03-11 33 views
9

Tôi có một ứng dụng cứ 15 phút một lần để sao chép từ cơ sở dữ liệu từ xa. Nó chỉ giữ hai kho lưu trữ đồng bộ. Một khi sao chép này là đi nó không thể làm điều đó một lần nữa. Tôi đã thiết lập cấu trúc sau nhưng tôi không chắc đó có phải là cách tiếp cận chính xác hay không.Cách khóa một phương thức java để bảo vệ nhiều lời gọi

public class ReplicatorRunner { 

     private static Lock lock = new ReentrantLock(); 

     public replicate() { 

      if (lock.tryLock()) { 
       try { 
        // long running process 
       } catch (Exception e) {     
       } finally { 
        lock.unlock(); 
       }    
      } else { 
       throw new IllegalStateException("already replicating"); 
      } 

     } 

} 

public class ReplicatorRunnerInvocator { 

    public void someMethod() { 

     try { 
      ReplicatorRunner replicator = new ReplicatorRunner(); 
      replicator.replicate(); 
     } catch (IllegalStateException e) { 
      e.printStackTrace(); 
     } 

    } 

} 

Các ReplicatorRunner là lớp sở hữu phương pháp replicate mà chỉ có thể chạy cùng một lúc.

Chỉnh sửa. Tôi cần cuộc gọi tiếp theo thất bại (không chặn) nếu phương thức đã chạy trên bất kỳ phiên bản nào.

+0

Có một câu hỏi ở đây nơi nào đó? – shoosh

+1

Yeap, trong tiêu đề ... dude, tôi không có thời gian để giúp bạn hoàn toàn nhưng kiểm tra từ khóa được đồng bộ ... –

+0

Đồng bộ hóa trên mỗi trường hợp hoặc mỗi lớp (nếu nó là tĩnh) và khối. Tôi muốn nó thất bại và không chặn. – rmarimon

Trả lời

4

Điều này có vẻ tốt. ReentrantLock.tryLock() sẽ chỉ cung cấp khóa cho một sợi, do đó, không cần thiết phải synchronized. Nó cũng ngăn chặn việc chặn vốn có trong đồng bộ hóa mà bạn nói là một yêu cầu. ReentrantLock là Serializable, vì vậy nên làm việc trên cụm của bạn.

.

+0

Tôi đang đi với điều này nhưng tôi phải kiểm tra xem mục nhập vào khối bị khóa với dòng sau để ngăn chặn nhiều cuộc gọi từ cùng một luồng: 'if (lock.tryLock() && getHoldCount() == 1) ' – rmarimon

+0

Thực sự ... tôi phải thay đổi thêm một lần nữa. Vì tôi đã khởi chạy một chuỗi để thực hiện phép tính dài, tôi không thể mở khóa khóa từ chuỗi khác đó. Tôi đã thay đổi logic để sử dụng semaphore với 1 giấy phép. Tôi sẽ đặt logic như một câu trả lời khác cho sự hoàn chỉnh. – rmarimon

0

hãy xem lớp Semaphore here hoặc đánh dấu phương thức là được đồng bộ luồng thực thi phương thức tại bất kỳ thời điểm đã định nào sở hữu một khóa trên đó tránh các chủ đề khác gọi phương thức cho đến khi kết thúc.
Chỉnh sửa: nếu bạn muốn các chủ đề khác không thành công, bạn có thể sử dụng Lock và kiểm tra xem khóa có được sử dụng theo phương pháp tryLock hay không.

1

Thay đổi public replicate()-public synchronized replicate()

Bằng cách đó lặp lại sẽ chỉ bao giờ cho phép truy cập vào một thread tại một thời điểm. Bạn cũng sẽ có thể xóa ReentrantLock và tất cả các mã liên quan.

+0

Chỉ có thể có một phương pháp lặp lại tại bất kỳ thời điểm nào vì nó sẽ làm hỏng bản sao nếu hai hoặc nhiều hơn làm điều đó. Việc đồng bộ hóa sẽ chặn trên cơ sở từng trường hợp. Tôi có thể đồng bộ hóa khối trên một lớp tĩnh nhưng điều đó sẽ chặn. Tôi cần thực hiện để thất bại nếu phương pháp đã chạy trên bất kỳ trường hợp nào. – rmarimon

0

Nếu không nhìn vào các chi tiết cụ thể của ReentrantLock, nó xảy ra với tôi rằng việc ngăn ngừa nhiều thói quen sao chép đồng thời này sẽ bị giới hạn trong một cá thể JVM duy nhất.

Nếu một phiên bản khác của lớp được khởi động trong một JVM riêng biệt, thì bạn có thể gặp sự cố.

Tại sao không đặt cơ chế khóa trên cơ sở dữ liệu? tức là Một hàng trong bảng điều khiển được đặt thành giá trị mô tả liệu bản sao có đang chạy bận hay không và đặt lại giá trị khi sao chép xong.

+0

Đúng. Các tính năng gói đồng thời khá tuyệt vời, nhưng chúng sẽ không xử lý đồng bộ hóa nhiều JVM. Kiểm soát nó ở cấp cơ sở dữ liệu có thể là lựa chọn tốt hơn của bạn ở đây. Hoặc bạn sẽ cần một cách để các trường hợp của bạn giao tiếp với nhau (RMI hoặc người khác) nhưng điều đó có thể trở nên phức tạp. – Etienne

+0

Sao chép xảy ra với bộ nhớ của JVM do đó không có vấn đề ở đó. Và chúng tôi có thể có nhiều JVM sao chép vào DB. Vấn đề không phải là DB là nhiều phương thức vô tình chạy bên trong JVM. – rmarimon

1

tôi đã kết thúc bằng cách sử dụng sau đây:

public class ReplicatorRunner { 

     private static Semaphore lock = new Semaphore(1); 

     public replicate() { 

      if (lock.tryAcquire()) { 
       try {        
        // basic setup     
        Thread t = new Thread(new Runnable() { 
         public void run() { 
          try { 
           // long running process        
          } catch Exception (e) { 
           // handle the exceptions 
          } finally { 
           lock.release(); 
          } 
         } 
        }) 
        t.start(); 

       } catch (Exception e) { 
        // in case something goes wrong 
        // before the thread starts 
        lock.release(); 
       }    
      } else { 
       throw new IllegalStateException("already replicating"); 
      } 

     } 

} 

public class ReplicatorRunnerInvocator { 

    public void someMethod() { 

     try { 
      ReplicatorRunner replicator = new ReplicatorRunner(); 
      replicator.replicate(); 
     } catch (IllegalStateException e) { 
      e.printStackTrace(); 
     } 

    } 

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