Java: Đối tượng Lock

Các khóa học qua video:
Python SQL Server PHP C# Lập trình C Java HTML5-CSS3-JavaScript
Học trên YouTube <76K/tháng. Đăng ký Hội viên
Viết nhanh hơn - Học tốt hơn
Giải phóng thời gian, khai phóng năng lực

Cho đến nay, phần Concurrency đã tập trung vào các API cấp thấp mà đã là một phần của nền tảng Java từ đầu. Những API này đủ dùng cho các tác vụ rất cơ bản, nhưng ta cần các khối xây dựng cấp cao hơn để có được những tác vụ nâng cao hơn. Điều này đặc biệt đúng đối với các ứng dụng đồng thời mang tính khai thác đầy đủ hệ thống đa lõi và đa xử lý hiện nay.

Trong phần này chúng ta sẽ xem xét một số các tính năng đồng thời cao cấp được giới thiệu từ phiên bản 5.0 của nền tảng Java. Hầu hết các tính năng này được thực hiện trong gói java.util.concurrent mới. Ngoài ra còn có các cấu trúc dữ liệu đồng thời mới trong Java Collections Framework:

  • Đối tượng Lock hỗ trợ khóa thành ngữ đơn giản hóa rất nhiều ứng dụng đồng thời.
  • Các bộ thực thi xác định một API cấp cao để tạo và quản lý luồng. Việc thực hiện bộ thực thi được cung cấp bởi java.util.concurrent sẽ quản trị một vùng lớn luồng phù hợp cho các ứng dụng quy mô lớn.
  • Bộ sưu tập đồng thời sẽ dễ dàng hơn trong việc quản lý một tập hợp lớn các dữ liệu, và có thể làm giảm đáng kể nhu cầu đồng bộ hóa.
  • Biến atomic có tính năng giảm thiểu sự đồng bộ hóa và giúp tránh các lỗi nhất quán bộ nhớ.
  • ThreadLocalRandom (trong JDK 7) cung cấp việc tạo hiệu quả các giá trị số giả ngẫu nhiên từ nhiều luồng.

Đối tượng Lock

Mã lệnh đồng bộ hóa dựa trên một loại khóa reentrant đơn giản. Đây là loại khóa dễ để sử dụng, nhưng có nhiều hạn chế. Nhiều thành ngữ khóa tinh vi được hỗ trợ bởi gói java.util.concurrent.locks. Chúng tôi sẽ không xem xét gói này một cách chi tiết, thay vào đó sẽ tập trung vào giao diện cơ bản nhất của nó là Lock.

Đối tượng Lock làm việc rất nhiều như các ổ khóa ngầm sử dụng bởi mã đồng bộ hóa. Như với ổ khóa tiềm ẩn, chỉ có một luồng là có thể sở hữu một đối tượng Lock tại một thời điểm. Đối tượng Lock cũng hỗ trợ cơ chế wait/notify thông qua mối liên quan đến các đối tượng Condition của nó.

Ưu điểm lớn nhất của đối tượng Lock thông quá khóa ngầm là khả năng của để trở lại trong một nỗ lực để có được một khóa. Phương thức tryLock sẽ sao lưu ra nếu khóa không có sẵn ngay lập tức hoặc trước thời gian chờ hết hạn (nếu được chỉ định). Phương thức lockInterruptibly sẽ sao lưu ra nếu luồng khác gửi một ngắt trước khi khóa được lấy lại.

Bạn có thể sử dụng đối tượng Lock để giải quyết vấn đề deadlock chúng ta đã tìm hiểu trong bài viết Liveness. Alphonse và Gaston tự đào tạo chính mình để nhận thấy khi một người bạn đang cúi chào. Chúng tôi mô hình hóa cải tiến này bằng cách yêu cầu rằng đối tượng Friend của chúng tôi phải có lock cho cả hai người tham gia trước khi tiếp tục hành động cúi chào. Dưới đây là mã nguồn cho mô hình cải tiến có tên Safelock. Để chứng minh tính linh hoạt của lock, chúng ta giả định rằng Alphonse và Gaston là quá say mê với khả năng mới tìm được để cúi chào một cách an toàn mà họ không thể dừng lại hành động được:

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.Random;

public class Safelock {
    static class Friend {
        private final String name;
        private final Lock lock = new ReentrantLock();

        public Friend(String name) {
            this.name = name;
        }

        public String getName() {
            return this.name;
        }

        public boolean impendingBow(Friend bower) {
            Boolean myLock = false;
            Boolean yourLock = false;
            try {
                myLock = lock.tryLock();
                yourLock = bower.lock.tryLock();
            } finally {
                if (! (myLock && yourLock)) {
                    if (myLock) {
                        lock.unlock();
                    }
                    if (yourLock) {
                        bower.lock.unlock();
                    }
                }
            }
            return myLock && yourLock;
        }

        public void bow(Friend bower) {
            if (impendingBow(bower)) {
                try {
                    System.out.format("%s: %s has"
                        + " bowed to me!%n",
                        this.name, bower.getName());
                    bower.bowBack(this);
                } finally {
                    lock.unlock();
                    bower.lock.unlock();
                }
            } else {
                System.out.format("%s: %s started"
                    + " to bow to me, but saw that"
                    + " I was already bowing to"
                    + " him.%n",
                    this.name, bower.getName());
            }
        }

        public void bowBack(Friend bower) {
            System.out.format("%s: %s has" +
                " bowed back to me!%n",
                this.name, bower.getName());
        }
    }

    static class BowLoop implements Runnable {
        private Friend bower;
        private Friend bowee;

        public BowLoop(Friend bower, Friend bowee) {
            this.bower = bower;
            this.bowee = bowee;
        }

        public void run() {
            Random random = new Random();
            for (;;) {
                try {
                    Thread.sleep(random.nextInt(10));
                } catch (InterruptedException e) {}
                bowee.bow(bower);
            }
        }
    }
           

    public static void main(String[] args) {
        final Friend alphonse =
            new Friend("Alphonse");
        final Friend gaston =
            new Friend("Gaston");
        new Thread(new BowLoop(alphonse, gaston)).start();
        new Thread(new BowLoop(gaston, alphonse)).start();
    }
}

» Tiếp: Giao diện (interface) Executor
« Trước: Đối tượng bất biến
Các khóa học qua video:
Python SQL Server PHP C# Lập trình C Java HTML5-CSS3-JavaScript
Học trên YouTube <76K/tháng. Đăng ký Hội viên
Viết nhanh hơn - Học tốt hơn
Giải phóng thời gian, khai phóng năng lực
Copied !!!