lock.lock()使用,与synchronized对比

Lock锁

锁实现提供了比使用synchronized方法和语句更广泛的锁操作。它们允许更灵活的结构,可能有不同的属性,可能支持多个关联的Condition对象。

锁是用于控制多个线程对共享资源的访问的工具。

通常,锁提供对共享资源的独占访问:一次只有一个线程可以获得锁,并且所有访问共享资源的访问都需要先获得锁。但是,有些锁可能允许并发访问共享资源。例如readwritellock的读锁。

同步方法或语句的使用提供了对每个对象关联的隐式监视器锁的访问,但强制所有锁的获取和释放都以块结构的方式进行:当多个锁被获取时,它们必须以相反的顺序被释放,并且所有的锁都必须在获取锁的同一个词法作用域中被释放。虽然同步方法和语句的作用域机制使使用监视器锁进行编程变得更加容易,并有助于避免许多涉及锁的常见编程错误,但在某些情况下,您需要以更灵活的方式使用锁。

例如,一些用于遍历并发访问的数据结构的算法需要使用“手拉手”或“链锁”:您获取节点A的锁,然后是节点B,然后释放A并获取C,然后释放B并获取D,等等。

Lock接口的实现允许在不同范围内获取和释放锁,并允许以任何顺序获取和释放多个锁,从而允许使用这种技术。

传统synchronized
synchronized是Java中的关键字,是一种同步锁。它修饰的对象有以下几种:

   1. 修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象;
      2. 修饰一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象;
                3. 修改一个静态的方法,其作用的范围是整个静态方法,作用的对象是这个类的所有对象;
                   4. 修改一个类,其作用的范围是synchronized后面括号括起来的部分,作用主的对象是这个类的所有对象。

lock.lock();

获得锁。如果锁不可用,那么为了线程调度目的,当前线程将被禁用,并处于休眠状态,直到获得锁。

实现注意事项Lock实现可以检测对锁的错误使用

例如可能导致死锁的调用,并可能在这种情况下抛出(未检查的)异常。环境和异常类型必须由该Lock实现记录。

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class lockTest {

    public static void main(String[] args) {
        Ticket ticket = new Ticket();

        new Thread(() -> {
            for (int i = 0; i < 40; i++) {
                ticket.sale(i);
            }
        }, "a").start();
        new Thread(() -> {
            for (int i = 0; i < 40; i++) {
                ticket.sale(i);
            }
        }, "b").start();
        new Thread(() -> {
            for (int i = 0; i < 40; i++) {
                ticket.sale(i);
            }
        }, "c").start();

    }
}

class Ticket {
    private int ticketNum = 30;
    private final Lock lock = new ReentrantLock();

    public void sale(int i) {
        lock.lock();
        try {
            if (this.ticketNum > 0) {
                System.out.println(Thread.currentThread().getName() + i + "-->购得第" + ticketNum-- + "张票, 剩余" + ticketNum + "张票");
            } else {
                System.out.println(Thread.currentThread().getName() + i + "-->没买到票,剩余" + ticketNum + "张票");
            }
            //睡眠一秒,增加错误的发生几率
            TimeUnit.SECONDS.sleep(1);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}

执行结果:

a0–>购得第30张票, 剩余29张票
a1–>购得第29张票, 剩余28张票
a2–>购得第28张票, 剩余27张票
a3–>购得第27张票, 剩余26张票
a4–>购得第26张票, 剩余25张票
a5–>购得第25张票, 剩余24张票
a6–>购得第24张票, 剩余23张票
a7–>购得第23张票, 剩余22张票
a8–>购得第22张票, 剩余21张票
b0–>购得第21张票, 剩余20张票
b1–>购得第20张票, 剩余19张票
b2–>购得第19张票, 剩余18张票
b3–>购得第18张票, 剩余17张票
c0–>购得第17张票, 剩余16张票
a9–>购得第16张票, 剩余15张票
a10–>购得第15张票, 剩余14张票
a11–>购得第14张票, 剩余13张票
a12–>购得第13张票, 剩余12张票
a13–>购得第12张票, 剩余11张票
a14–>购得第11张票, 剩余10张票
a15–>购得第10张票, 剩余9张票
a16–>购得第9张票, 剩余8张票
a17–>购得第8张票, 剩余7张票
a18–>购得第7张票, 剩余6张票
a19–>购得第6张票, 剩余5张票
a20–>购得第5张票, 剩余4张票
a21–>购得第4张票, 剩余3张票
a22–>购得第3张票, 剩余2张票
a23–>购得第2张票, 剩余1张票
b4–>购得第1张票, 剩余0张票
c1–>没买到票,剩余0张票
a24–>没买到票,剩余0张票
a25–>没买到票,剩余0张票
a26–>没买到票,剩余0张票
a27–>没买到票,剩余0张票

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值