Java多线程之同步锁-lock详解
前言
在多线程编程中,同步是一项非常重要的概念,同步控制的目的是为了保证线程安全,避免由于多线程操作导致的数据混乱等问题。在Java中,同步机制有多种实现方式,其中Lock是比较常用的一种。
Lock与synchronized的对比
在Java早期版本中,synchronized是主流的同步控制方式,但是synchronized有一些缺点:只能在代码块或方法上进行加锁,无法灵活地进行控制,且性能相对较低。
为了解决这些问题,Java 5引入了Lock接口,Lock机制可以带来更好的性能以及更灵活的控制方式。
Lock机制具有以下优点:
- 支持选择性地进行锁操作(在某些场景下能提升性能的效果)
- 支持公平锁操作
- 多样化的同步方式
Lock接口详解
Lock接口定义
Lock接口是Java提供的一种同步机制,它定义了锁的基本操作,包括获取锁、释放锁等。
public interface Lock {
void lock();
void lockInterruptibly() throws InterruptedException;
boolean tryLock();
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
void unlock();
Condition newCondition();
}
- lock():获取锁,如果锁被占用,则一直等待,直到获取到锁
- lockInterruptibly():获取锁,但是会响应中断,如果锁被占用,当前线程会处于等待状态,此时如果线程被中断,就会抛出InterruptedException异常
- tryLock():非阻塞地获取锁,如果锁被占用,则直接返回false
- tryLock(long time, TimeUnit unit):在指定的时间内获取锁,如果在指定时间内没有获取到锁,则返回false
- unlock():释放锁
- newCondition():获取一个等待/通知机制
Lock的简单应用示例
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class LockDemo {
public static void main(String[] args) {
// 创建一个Lock锁对象
Lock lock = new ReentrantLock();
// 获取锁
lock.lock();
try {
// 此处为业务代码,需要保证线程安全
} finally {
// 释放锁
lock.unlock();
}
}
}
Condition接口详解
Condition接口是Lock接口的一个附属接口,它提供了一种类似wait/notify的机制,用于多线程之间的等待/通知(wait/notify)机制。
public interface Condition {
void await() throws InterruptedException;
void awaitUninterruptibly();
long awaitNanos(long nanosTimeout) throws InterruptedException;
boolean await(long time, TimeUnit unit) throws InterruptedException;
boolean awaitUntil(Date deadline);
void signal();
void signalAll();
}
- await():使当前线程等待直到被唤醒或中断,效果类似于wait()方法
- awaitUninterruptibly():与await()方法类似,但是它不会响应中断
- awaitNanos(long nanosTimeout):使当前线程等待指定时间或被唤醒或中断,效果类似于wait(long timeout)方法
- await(long time, TimeUnit unit):与awaitNanos()方法类似,但是它使用了TimeUnit来指定时间单位
- awaitUntil(Date deadline):使当前线程等待直到被唤醒、中断或者到达指定时间,效果类似于wait(long timeout)方法
- signal():唤醒一个等待在Condition上的线程
- signalAll():唤醒所有等待在Condition上的线程
Condition的简单应用示例
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ConditionDemo {
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
public void method1() {
lock.lock();
try {
// 做一些业务代码
// 线程1等待
condition.await();
// 线程1被唤醒后,继续执行
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void method2() {
lock.lock();
try {
// 做一些业务代码
// 线程2唤醒线程1
condition.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public static void main(String[] args) {
ConditionDemo conditionDemo = new ConditionDemo();
new Thread(() -> conditionDemo.method1(), "Thread1").start();
new Thread(() -> conditionDemo.method2(), "Thread2").start();
}
}
在上面的示例中,我们创建了一个Condition对象,并在method1()方法中调用了await()方法进入等待状态,然后在method2()方法中调用了signal()方法唤醒等待在Condition上的线程。
总结
Lock机制相比synchronized的优点如下:
- 支持可重入性,提供更高的灵活性
- 支持公平锁和非公平锁
- 支持多个条件变量,实现更灵活的等待/通知模型
但是Lock机制也有一些缺点:
- 代码编写相对复杂
- 需要手动加锁和释放锁,容易出错
因此,选择使用Lock机制或synchronized机制应该视情况而定,需要根据具体需求来进行选择。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java多线程之同步锁-lock详解 - Python技术站