Java并发编程-Lock接口的认识和使用

1.Lock是一个接口,定义了一系列的获取和释放锁的方法。

接口  备注
lock() 获取锁,获取不到则阻塞
tryLock() 尝试获取锁,如果获取不到立即返回
tryLock(long time, TimeUnit unit) 在指定时间内尝试获取锁,如果获取不到立即返回
lockInterruptedly() 获取锁时可以响应中断

2.Lock和synchronized的比较

Lock需要显示地获取和释放锁,繁琐但更灵活,可以方便的实现公平性地获取锁,非阻塞地获取锁,能被中断地获取锁,超时获取锁。synchronized不需要显示地获取和释放锁,使用简单,但是不灵活。

3.自己实现一个锁

public class MyLock implements Lock {

    private boolean isLocked = false;

    @Override
    public synchronized void lock() {
        while (isLocked) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        isLocked = true;
    }

    @Override
    public void lockInterruptibly() throws InterruptedException {
    }

    @Override
    public boolean tryLock() {
        return false;
    }

    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return false;
    }

    @Override
    public synchronized void unlock() {
        isLocked = false;
        notify();
    }

    @Override
    public Condition newCondition() {
        return null;
    }
}

解决计数器线程安全问题。

public class Sequence {

    private int value;
    private MyLock lock = new MyLock();

    public int getNext() {
        try {
            lock.lock();
            return value++;
        } finally {
            lock.unlock();
        }
    }

public static void main(String[] args) {

        final Sequence s = new Sequence();

        for (int i = 0; i < 4; i++) {
            new Thread(new Runnable() {
                public void run() {
                    while (true) {
                        System.out.println(Thread.currentThread().getName() + " " + s.getNext());
                        try {
                            Thread.sleep(500L);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }).start();
        }
    }
}

3.可重入锁

使用第3步我们自己实现的锁完成以下代码。

public class Demo {

    private MyLock lock = new MyLock();

    public void a() {
        lock.lock();
        System.out.println("a");
        b();
        lock.unlock();
    }

    public void b() {
        lock.lock();
        System.out.println("b");
        lock.unlock();
    }

    public static void main(String[] args) {
        Demo demo = new Demo();
        demo.a();
    }

}

运行后我们发现只打印出来了a,并且程序没有退出。这是因为第三步我们实现的锁不是可重入的,在方法a中获取了锁,但在执行方法b时还需要获取锁,但此时锁有没有被自己释放,所以线程被自己阻塞。为了解决这种问题,我们可以实现自己的可重入锁,可重入锁的意思是一个线程获得锁以后,再次获取相同的锁不用进行同步操作,可以直接获取锁。

public class MyReentrantLock implements Lock {

    private boolean isLocked = false;
    private Thread lockBy = null;
    private int lockCount = 0;

    @Override
    public synchronized void lock() {
        Thread currentThread = Thread.currentThread();
        while (isLocked && currentThread != lockBy) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        isLocked = true;
        lockBy = currentThread;
        lockCount++;
    }

    @Override
    public synchronized void unlock() {
        if (lockBy == Thread.currentThread()) {
            lockCount--;
            if (lockCount == 0) {
                isLocked = false;
                 notifyAll();
            }
        }
    }

    @Override
    public void lockInterruptibly() throws InterruptedException {
    }

    @Override
    public boolean tryLock() {
        return false;
    }

    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return false;
    }

    @Override
    public Condition newCondition() {
        return null;
    }

}

验证

public class Demo2 {

    private MyReentrantLock lock = new MyReentrantLock();

    public void a() {
        lock.lock();
        System.out.println("a");
        b();
        lock.unlock();
    }

    public void b() {
        lock.lock();
        System.out.println("b");
        lock.unlock();
    }

    public static void main(String[] args) {
        Demo2 demo2 = new Demo2();
        demo2.a();
    }

}

运行后可以看到a,b都打印出来了,即实现了锁的重入。

猜你喜欢

转载自blog.csdn.net/qq_22866497/article/details/80589626