Java多线程中Lock锁的使用总结
什么是Lock?
在Java中,Lock是一种比synchronized更加灵活、功能更加强大的线程同步机制。它可以提供比传统的synchronized更为广泛的锁定操作。
Lock和synchronized的对比
- 锁的获取方式
synchronized是隐式获取锁,只要进入synchronized保护的代码段,锁就会自动获得,退出代码段时锁会自动释放。
而在使用Lock时,需要在代码中显式地获得和释放锁,如果没有正确释放锁,就可能导致死锁等问题。
- 粒度
使用synchronized时,锁粒度相对较粗,只能在代码块或者方法上进行同步,无法对其中的代码片段进行细粒度的控制。
而使用Lock时可以对某个资源进行单独的加锁和解锁,这就可以避免对整个代码块进行锁定,提高多线程执行的效率。
- 等待可中断
在synchronized中,如果等待获取锁的线程一直没有获取到锁,就只能一直等待下去。
而在Lock中,获取锁的操作可以设置等待时间,如果等待时间超过一定的范围仍然没有获取到锁,就可以中断等待,防止死锁的发生。
- 公平锁
synchronized是一种非公平锁,锁获取的顺序由系统随机决定,无法保证等待时间最长的线程一定会先获取锁。
而Lock可以通过构造方法设置是否为公平锁,公平锁保证等待时间最长的线程先获取锁,避免了某些线程长时间得不到锁的问题。
Lock的使用示例
示例一:非公平锁
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class LockTest {
private Lock lock = new ReentrantLock(false);
// false 表示这是一个不公平锁,默认为 false
public void print() {
lock.lock();
try {
System.out.println(Thread.currentThread().getName() + " get lock");
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public static void main(String[] args) {
final LockTest lockTest = new LockTest();
Runnable runnable = () -> {
System.out.println(Thread.currentThread().getName() + " start");
lockTest.print();
};
new Thread(runnable, "thread1").start();
new Thread(runnable, "thread2").start();
}
}
输出结果如下:
thread1 start
thread2 start
thread1 get lock
thread2 get lock
可以看到,在不公平锁的情况下,获得锁的线程是随机的。
示例二:可重入锁
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class LockTest {
private Lock lock = new ReentrantLock();
public void print() {
lock.lock();
try {
System.out.println(Thread.currentThread().getName() + " get outer lock");
Thread.sleep(1000);
lock.lock();
try {
System.out.println(Thread.currentThread().getName() + " get inner lock");
} finally {
lock.unlock();
}
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println(Thread.currentThread().getName() + " unlock outer lock");
lock.unlock();
}
}
public static void main(String[] args) {
final LockTest lockTest = new LockTest();
Runnable runnable = () -> {
System.out.println(Thread.currentThread().getName() + " start");
lockTest.print();
};
new Thread(runnable, "thread1").start();
new Thread(runnable, "thread2").start();
}
}
输出结果如下:
thread1 start
thread2 start
thread1 get outer lock
thread1 get inner lock
thread1 unlock outer lock
thread2 get outer lock
thread2 get inner lock
thread2 unlock outer lock
在可重入锁的情况下,同一个线程在获得锁后,可以再次获得该锁而不会被阻塞。在上面的示例中,线程1先获得了锁,在获得锁之后,又顺利地获得了一次该锁,因为是同一个线程,所以不会被阻塞。而线程2在获取锁之后也可以顺利地获取第二次锁。这个叫做可重入锁也叫做递归锁。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java多线程中Lock锁的使用总结 - Python技术站