介绍
从JDK5之后,Java提供了另外一种线程同步机制:它通过显示定义同步锁对象来实现同步,在这种机制下,同步锁应该使用Lock对象充当。
通常认为:Lock提供了比synchronized方法和synchronized代码块更广泛的锁定操作,Lock实现允许更灵活的结构,可以具有差别很大的属性,并且可以支持多个相关的Condition对象。
Lock是控制多个线程对共享资源进行访问的工具。通常,所提供了对共享资源的独占访问,每次只能有一个线程对Lock对象加锁,线程开始访问共享资源之前应先获得Lock对象。不过,某些可能允许对共享资源的并发访问,如ReadWriteLock(读写锁)。当然,在实现线程安全的控制中,通常喜欢使用ReentrantLock(可重入锁)。使用该Lock对象可以显示加锁、释放锁。
synchronized和Lock锁比较
synchronized: 不灵活,效率慢,自动挡(自动上锁,自动释放锁)
lock锁:灵活,手动挡(手动上锁,手动释放锁)
如何使用lock代替synchronized,下面看一下正常的synchronized使用方式
public class ThreadLock extends Thread{
Ticket ticket;
public void run() {
synchronized(ticket){
while (ticket.count > 0) {
System.out.println("当前票数:"+ticket.count--);
}
}
}
public ThreadLock(Ticket ticket) {
super();
this.ticket = ticket;
}
public static void main(String[] args) {
Ticket ticket = new Ticket();
for (int i = 0 ;i<3;i++) {
new ThreadLock(ticket).start();
}
}
}
class Ticket {
public int count = 10;
}
程序输出,并没有线程安全问题。然后看一下lock代码
/**
* 线程锁测试
* @author terry
* @date 2018年5月27日
*/
public class ThreadLock extends Thread{
Ticket ticket;
//创建一个锁对象
public void run() {
ticket.lock.lock();//锁
while (ticket.count > 0) {
System.out.println("当前票数:"+ticket.count--);
}
ticket.lock.unlock();//释放锁
}
public ThreadLock(Ticket ticket) {
super();
this.ticket = ticket;
}
public static void main(String[] args) {
Ticket ticket = new Ticket();
for (int i = 0 ;i<3;i++) {
new ThreadLock(ticket).start();
}
}
}
class Ticket {
public int count = 10;
public Lock lock = new ReentrantLock();
}
可以看到一样的打印结果
在调用lock.lock()方法要的一点:如果在unlock调用之前出现了异常,那么该线程就会一直被锁住。
如果在执行到count为2出发生了异常,模拟如下:
public class ThreadLock extends Thread{
Ticket ticket;
//创建一个锁对象
public void run() {
ticket.lock.lock();
while (ticket.count > 0) {
if (ticket.count == 2) {
throw new RuntimeException("发生异常!");
}
System.out.println("当前票数:"+ticket.count--);
}
ticket.lock.unlock();
}
public ThreadLock(Ticket ticket) {
super();
this.ticket = ticket;
}
public static void main(String[] args) {
Ticket ticket = new Ticket();
for (int i = 0 ;i<3;i++) {
new ThreadLock(ticket).start();
}
}
}
class Ticket {
public int count = 10;
public Lock lock = new ReentrantLock();
}
程序一直在执行
那么我们需要把unlock写在finally中
代码如下:
/**
* 线程锁测试
* @author terry
* @date 2018年5月27日
*/
public class ThreadLock extends Thread{
Ticket ticket;
//创建一个锁对象
public void run() {
ticket.lock.lock();
while (ticket.count > 0) {
if (ticket.count == 2) {
throw new RuntimeException("发生异常!");
}
System.out.println("当前票数:"+ticket.count--);
}
ticket.lock.unlock();
}
public ThreadLock(Ticket ticket) {
super();
this.ticket = ticket;
}
public static void main(String[] args) {
Ticket ticket = new Ticket();
for (int i = 0 ;i<3;i++) {
new ThreadLock(ticket).start();
}
}
}
class Ticket {
public int count = 10;
public Lock lock = new ReentrantLock();
}
发生异常后,该线程停止了