Lock锁,可以得到和 synchronized一样的效果,即实现原子性、有序性和可见性。

相较于synchronized,Lock锁可手动获取锁和释放锁、可中断的获取锁、超时获取锁。

Lock 是一个接口,两个直接实现类:ReentrantLock(重入锁), ReentrantReadWriteLock(读写锁)。

1. 概述

Lock锁,使用时手动获取锁和释放锁,比synchronized更加灵活;可中断的获取锁;超时获取锁。

Lock 锁的基本用法, l.lock()方法进行上锁, l.unlock()方法进行解锁,如下所示。

 Lock l = ...;
 l.lock(); // 上锁
 try {
   // access the resource protected by this lock
 } finally {
   l.unlock(); // 解锁
 }

2. Lock锁的API

修饰符和类型方法描述
voidlock()获得锁。
voidlockInterruptibly​()获得锁,可中断。举个例子,当两个线程同时通过lock.lockInterruptibly()想获取某个锁时,假若此时线程A获取到了锁,而线程B只有在等待,那么对线程B调用threadB.interrupt()方法能够中断线程B的等待过程。
booleantryLock​()锁在空闲的才能获取锁(未获得锁不会等待)。举个例子:当两个线程同时通过lock.trylock()想获取某个锁时,假若此时线程A获取到了锁,而线程B不会等待,直接放弃获取锁。
booleantryLock​(long time, TimeUnit unit)

如果锁定可用,则此方法立即返回值true

如果锁不可用,则当前线程将被禁用以进行线程调度,并且在发生以下三种情况之一之前处于休眠状态:

  • 当前线程获取锁。
  • 其他一些线程中断当前线程。
  • 等待时间过去了,返回false
voidunlock​()释放锁。

3. lock() 方法,unlock()方法

创建一个 Lock 锁:

Lock l = new ReentrantLock();

给代码块上锁:

        l.lock();
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName() + ": ");
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        l.unlock();

全部代码:

package lock;

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

public class MyLockStudy implements Runnable {

    private int count;
    Lock l = new ReentrantLock();

    @Override
    public void run() {
        l.lock();
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName() + ": ");
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        l.unlock();
    }

    public static void main(String args[]) {
        MyLockStudy runn = new MyLockStudy();
        Thread thread1 = new Thread(runn, "thread1");
        Thread thread2 = new Thread(runn, "thread2");
        Thread thread3 = new Thread(runn, "thread3");
        thread1.start();
        thread2.start();
        thread3.start();
    }
}

运行截图:

4. tryLock()方法

tryLock​(),锁在空闲的才能获取锁(未获得锁不会等待,lock()未获得锁会进入阻塞状态 ),返回值为boolean类型,获取锁则为 true ,反之为 false。

tryLock() 进行加锁:

        if (l.tryLock()) {
            System.out.println(Thread.currentThread().getName() + "获取锁");
            for (int i = 0; i < 5; i++) {
                System.out.println(Thread.currentThread().getName() + ": ");
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            l.unlock();
        } else {
            System.out.println(Thread.currentThread().getName() + "未获取锁");
        }

完整代码: 

package lock;

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

public class MyLockStudy implements Runnable {

    private int count;
    Lock l = new ReentrantLock();

    @Override
    public void run() {
        if (l.tryLock()) {
            System.out.println(Thread.currentThread().getName() + "获取锁");
            for (int i = 0; i < 5; i++) {
                System.out.println(Thread.currentThread().getName() + ": ");
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            l.unlock();
        } else {
            System.out.println(Thread.currentThread().getName() + "未获取锁");
        }

    }

    public static void main(String args[]) {
        MyLockStudy runn = new MyLockStudy();
        Thread thread1 = new Thread(runn, "thread1");
        Thread thread2 = new Thread(runn, "thread2");
        Thread thread3 = new Thread(runn, "thread3");
        thread1.start();
        thread2.start();
        thread3.start();
    }
}

运行截图如下所示:

5. tryLock​(long time, TimeUnit unit) 方法

如果锁定可用,则此方法立即返回值true。如果锁不可用,则当前线程将被禁用以进行线程调度,并且在发生以下三种情况之一之前处于休眠状态:

  • 当前线程获取锁。
  • 其他一些线程中断当前线程。
  • 等待时间过去了,返回false

设置等待时间为 1000 毫秒。

        try {
            if (l.tryLock(1000, TimeUnit.MILLISECONDS)) {
                System.out.println(Thread.currentThread().getName() + "获取锁");
                for (int i = 0; i < 5; i++) {
                    System.out.println(Thread.currentThread().getName() + ": ");
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                l.unlock();
            } else {
                System.out.println(Thread.currentThread().getName() + "未获取锁");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

完整代码如下所示:

package lock;

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

public class MyLockStudy implements Runnable {

    private int count;
    Lock l = new ReentrantLock();

    @Override
    public void run() {
        try {
            if (l.tryLock(1000, TimeUnit.MILLISECONDS)) {
                System.out.println(Thread.currentThread().getName() + "获取锁");
                for (int i = 0; i < 5; i++) {
                    System.out.println(Thread.currentThread().getName() + ": ");
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                l.unlock();
            } else {
                System.out.println(Thread.currentThread().getName() + "未获取锁");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

    public static void main(String args[]) {
        MyLockStudy runn = new MyLockStudy();
        Thread thread1 = new Thread(runn, "thread1");
        Thread thread2 = new Thread(runn, "thread2");
        Thread thread3 = new Thread(runn, "thread3");
        thread1.start();
        thread2.start();
        thread3.start();
    }
}

运行截图:

如果锁不可用,则当前线程将被禁用以进行线程调度,并且在发生以下三种情况之一之前处于休眠状态,当前线程是可以被中断的。

package lock;

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

public class MyLockStudy implements Runnable {

    private int count;
    Lock l = new ReentrantLock();

    @Override
    public void run() {
        try {
            if (l.tryLock(1000, TimeUnit.MILLISECONDS)) {
                System.out.println(Thread.currentThread().getName() + "获取锁");
                for (int i = 0; i <= 500000000; i++) {
                    if (i == 500000000) {
                        System.out.println("运算结束");
                    }
                }
                l.unlock();
            } else {
                System.out.println(Thread.currentThread().getName() + "未获取锁");
            }
        } catch (InterruptedException e) {
            System.out.println("中断");
            e.printStackTrace();
        }

    }

    public static void main(String args[]) {
        MyLockStudy runn = new MyLockStudy();
        Thread thread1 = new Thread(runn, "thread1");
        Thread thread2 = new Thread(runn, "thread2");
        Thread thread3 = new Thread(runn, "thread3");
        thread1.start();
        thread2.start();
        thread3.start();
        try {
            TimeUnit.MILLISECONDS.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        thread1.interrupt();
        thread2.interrupt();
        thread3.interrupt();
    }
}

线程1获取了锁,其他线程休眠,然后被中断。 

 

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐