Đồng thời, BlockingQueues (Java 7) - 1

"Chào, Amigo!"

"Chào Kim!"

"Hôm nay, tôi sẽ nói với bạn về đồng thời."

" Đồng thời là một thư viện lớp Java bao gồm các lớp đặc biệt đã được tối ưu hóa để làm việc từ nhiều luồng. Đây là một chủ đề rất thú vị và bao quát. Nhưng hôm nay chúng ta sẽ chỉ giới thiệu. Gói này có tên là java.util. gói concurrent. Tôi sẽ kể cho bạn nghe về một vài lớp học thú vị."

" Các loại nguyên tử. "

"Bạn đã biết rằng số chẵn ++ không phải là một thao tác an toàn cho luồng. Khi một biến được tăng thêm 1, ba thao tác thực sự diễn ra. Kết quả là, có thể xảy ra xung đột khi biến được thay đổi."

"Ừ, Ellie đã nói với tôi cách đây không lâu:"

chủ đề 1 chủ đề 2 Kết quả
register1 = count;
register1++;
count = register1;
register2 = count;
register2++;
count = register2;
register1 = count;
register2 = count;
register2++;
count = register2;
register1++;
count = register1;

"Chính xác. Sau đó, Java đã thêm các kiểu dữ liệu để thực hiện các thao tác này như một, tức là về mặt nguyên tử (một nguyên tử không thể chia cắt được)."

"Ví dụ: Java có AtomicInteger, AtomicBoolean, AtomicDouble , v.v."

"Giả sử chúng ta cần tạo một lớp «bộ đếm»:"

Ví dụ
class Counter
{
 private int c = 0;

 public void increment()
 {
  c++;
 }

 public void decrement()
 {
  c--;
 }

 public int value()
 {
  return c;
 }
}

"Làm thế nào để bạn làm cho các đối tượng của lớp này trở nên an toàn?"

"Chà, tôi sẽ làm cho tất cả các phương thức được đồng bộ hóa và hoàn thành nó:"

Ví dụ
class synchronized Counter
{
 private int c = 0;

 public synchronized void increment()
 {
  c++;
 }

 public synchronized void decrement()
 {
  c--;
 }

 public synchronized int value()
 {
  return c;
 }
}

"Làm tốt lắm. Nhưng, nó sẽ trông như thế nào nếu chúng ta sử dụng các loại nguyên tử:"

Ví dụ
class AtomicCounter
{
 private AtomicInteger c = new AtomicInteger(0);

 public void increment()
 {
  c.incrementAndGet();
 }

 public void decrement()
 {
  c.decrementAndGet();
 }

 public int value()
 {
  return c.get();
 }
}

"Lớp của bạn và lớp của tôi đều hoạt động theo cùng một cách, nhưng lớp có AtomicInteger hoạt động nhanh hơn."

"Chà, nó có phải là một sự khác biệt nhỏ không?"

"Vâng. Dựa trên kinh nghiệm của tôi, tôi luôn khuyên bạn nên sử dụng đồng bộ hóa. Chỉ khi tất cả mã ứng dụng đã được viết xong và quá trình tối ưu hóa đã bắt đầu, bạn mới nên bắt đầu viết lại mã để sử dụng các loại nguyên tử. Nhưng trong mọi trường hợp, tôi muốn bạn để biết rằng những loại như vậy tồn tại. Ngay cả khi bạn không chủ động sử dụng chúng, thì luôn có khả năng bạn gặp phải mã nơi chúng được sử dụng."

"Tôi đồng ý. Điều đó có ý nghĩa."

"Nhân tiện, bạn có nhận thấy rằng các loại nguyên tử không phải là bất biến không ? Ngược lại với lớp Integer tiêu chuẩn , AtomicInteger chứa các phương thức để thay đổi trạng thái bên trong của nó."

"Hiểu rồi. Giống như StringStringBuffer ."

"Ừ, đại loại như vậy."

" Bộ sưu tập an toàn cho luồng. "

"Ví dụ về một bộ sưu tập như vậy, tôi có thể trình bày ConcurrentHashMap không. Bạn sẽ làm cho chuỗi HashMap an toàn như thế nào?"

"Làm cho tất cả các phương pháp của nó được đồng bộ hóa?"

"Chắc chắn rồi, nhưng bây giờ hãy tưởng tượng rằng bạn có một Bản đồ đồng bộ hóa như vậy và hàng chục luồng truy cập vào nó. Và hàng trăm lần một giây một mục nhập mới được thêm vào bản đồ và trong quá trình này, toàn bộ đối tượng bị khóa để đọc và ghi."

"Chà, đây là cách tiếp cận tiêu chuẩn. Bạn có thể làm gì?"

"Những người tạo ra Java đã nghĩ ra một số điều thú vị."

"Đầu tiên, chúng lưu trữ dữ liệu trong ConcurrentHashMap trong một khối duy nhất, nhưng chia nó thành các phần gọi là 'bộ chứa'. Và khi ai đó thay đổi dữ liệu trong Bản đồ đồng thời, thì chúng tôi chỉ khóa bộ chứa đang được truy cập chứ không phải toàn bộ đối tượng. Mặt khác từ, nhiều luồng có thể thay đổi đối tượng đồng thời."

"Thứ hai, bạn có nhớ rằng bạn không thể lặp lại các thành phần của danh sách/bản đồ và thay đổi danh sách cùng một lúc không? Mã như vậy sẽ đưa ra một ngoại lệ:"

Không lặp lại các phần tử của bộ sưu tập trong một vòng lặp và đồng thời thay đổi nó
HashMap<String, Integer> map = new HashMap<String, Integer>();

for (String key: map.keySet())
{
 if (map.get(key) == 0)
  map.remove(key);
}

"Nhưng trong ConcurrentHashMap, bạn có thể:"

Đừng lặp lại các thành phần của bộ sưu tập trong một vòng lặp và đồng thời thay đổi nó"
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<String, Integer>();

for (String key: map.keySet())
{
 if (map.get(key) == 0)
  map.remove(key);
}

"Gói đồng thời có nhiều ưu điểm. Chúng ta chỉ cần hiểu rất rõ các lớp này để sử dụng chúng."

"Tôi hiểu rồi. Cảm ơn, Kim. Đây là những lớp học thực sự thú vị. Tôi hy vọng rằng một ngày nào đó tôi sẽ thành thạo chúng như một bậc thầy."