Lock锁、ReentrantLock可重入锁使用
Lock锁
-
jdk 5.0开始,Java提供了更强大的线程同步机制,可以显示定义同步锁对象来实现同步。同步锁使用Lock对象充当。
-
java.util.concurrent.locks.Lock接口是控制多个线程对共享资源进行访问的工具。锁提供了对共享资源的独占访问,每次只能有一个线程对Lock对象加锁,线程开始访问共享资源之前需要先获得Lock对象。
-
ReentrantLock(可重入锁)类实现了Lock,它拥有与sychronized相同的并发性和内存语义,在实现线程安全的控制中,比较常用的是ReentrantLock,它可以显示的加锁、释放锁
ReentrantLock(可重入锁)使用
不使用锁,多个线程可能拿到相同票号
package testthread.gaoji;
/**
* 以买票为例,三个线程操作共同的票资源
*/
public class TestLock {
public static void main(String[] args) {
TicketThread ticketThread = new TicketThread();
Thread thread1 = new Thread(ticketThread, "黄牛");
Thread thread2 = new Thread(ticketThread, "12306");
Thread thread3 = new Thread(ticketThread, "美团");
thread1.start();
thread2.start();
thread3.start();
}
}
class TicketThread implements Runnable {
int ticketNums = 10;
@Override
public void run() {
while (ticketNums > 0) {
System.out.println(Thread.currentThread().getName() + "获得票号" + ticketNums--);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
输出:
12306获得票号10
黄牛获得票号9
美团获得票号10
12306获得票号8
美团获得票号7
黄牛获得票号6
12306获得票号5
美团获得票号3
黄牛获得票号4
黄牛获得票号2
美团获得票号2
12306获得票号1
加锁后,变成同步的,每次只有一个线程操作代码块
package testthread.gaoji;
import java.util.concurrent.locks.ReentrantLock;
/**
* 以买票为例,三个线程操作共同的票资源
*/
public class TestLock2 {
public static void main(String[] args) {
TicketThread2 ticketThread = new TicketThread2();
new Thread(ticketThread, "黄牛").start();
new Thread(ticketThread, "12306").start();
new Thread(ticketThread, "美团").start();
}
}
class TicketThread2 implements Runnable {
volatile int ticketNums = 10;
//定义Lock锁 为了安全用private final来修饰
private final ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
try {
//加锁:一般放在try里边,和需要加锁的方法体一起
lock.lock();
while (ticketNums > 0) {
System.out.println(Thread.currentThread().getName() + "获得票号" + ticketNums--);
Thread.sleep(0);
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
//解锁:一般都是finally解锁,确保肯定会执行解锁操作
lock.unlock();
}
}
}
输出:
黄牛获得票号10
黄牛获得票号9
黄牛获得票号8
黄牛获得票号7
黄牛获得票号6
黄牛获得票号5
黄牛获得票号4
黄牛获得票号3
黄牛获得票号2
黄牛获得票号1
synchronized与Lock对比
- Lock是显示加锁(手动开启和关闭锁,切记要关闭锁),synchronized是隐式锁,出了作用域自动释放
- Lock只有代码块锁,synchronized有方法锁和代码块锁
- 使用Lock锁,JVM将花费较少的时间来调度线程,性能更好。并且具有更好的扩展性(提供更多的子类)
- 优先使用顺序:Lock > 同步代码块(已经进入了方法体,分配了相应资源) > 同步方法(在方法体之外)