Java并发包JUC的Lock锁讲解

本文深入探讨Java中的两种锁机制:Synchronized与Lock的区别与应用场景。包括它们的基本概念、使用方式及如何实现线程间的通信。并通过消费者生产者模式实例对比两者在实际应用中的差异。
概述

Java有两种锁,一种是使用关键字Synchronized对方法或者代码块进行加锁,一种是使用接口Lock(实际上其实现类)进行上锁和解锁。

区别:

  • Synchronized是java的一个关键字,而Lock是一个java类。
  • Synchronized是一个“自动”的“隐式”锁,也就是只要在方法或者代码块上加上该关键字,就会实现自动的上锁和解锁,而Lock是一个非自动的显式锁,上锁和解锁都需要用代码显示指定。如果不显式释放锁,就会造成死锁。
  • Synchronized是可重入、非公平锁。而Lock锁是可重入,公平/非公平锁,通过设置可以设置为公平锁或者非公平锁。
  • Synchronized修饰成员方法锁是这个对象本身,修饰静态方法的锁是类对象,修饰代码块时可以指定任意非null对象。而Lock锁的锁就是这个Lock对象。
使用

Lock接口有三个实现类:

  • ReentrantLock:可重入锁,可以代替上面synchronized关键字的使用。
  • ReentrantReadWriteLock.ReadLock :读锁。
  • ReentrantReadWriteLock.WriteLock:写锁。
    读锁与写锁总是成对存在的,以实现对资源的合理访问,如果使用普通的可重入锁的话,无论是对资源的读和写,都是排他的。如果使用读写锁,那么在资源处于读锁状态时,其他读操作也可以进来访问,写操作就不行,如果处于写锁状态时,那么其他读写操作都不能访问。可以实现并发度、排他写。
可重入锁ReentrantLock的使用:
public class LockDemo {
   
   

    //创建一个锁对象
    private static Lock lock = new ReentrantLock();

    public static void main(String[] args){
   
   
    	//代码就是开始是个线程,然后每个线程对以共享变量num循环自增十次。正确输出结果是100
        testReentrantLock();
    }


    public static void testReentrantLock(){
   
   
        Integer num = 0;
        Data data = new Data(num);
        for (int i = 0;i<10;i++){
   
   
            new Thread(data).start();
        }

    }

    static class Data implements Runnable{
   
   
        private Integer num;


        public Data(Integer num){
   
   
            this.num = num;
        }
        @Override
        public void run() {
   
   
            for (int i = 0;i<10;i++){
   
   
                //上锁
                lock.lock();
                try {
   
   
                    try {
   
   
                        //这里睡眠一毫米是为了让效果更佳明显
                        TimeUnit.MILLISECONDS.sleep(1);
                    } catch (InterruptedException e) {
   
   
                        e.printStackTrace();
                    }
                    num ++;
                    System.out.println(num);
                }finally {
   
   
                    //释放锁
                    lock.unlock();
                }

            }
        }
    }
}

结果:正确
在这里插入图片描述
去掉上锁、解锁的代码。结果错误。
在这里插入图片描述

还可以给获取锁设置一个超时时间,时间过了还没获取到锁,就返回一个false并抛出一个中断异常。获取到锁就返回true。

//使用该方法获取锁,可以设置超时,使得线程不会永久阻塞。
boolean tryLock(long time, TimeUnit unit) 
使用Synchronized和ReentrantLock实现一个消费者生产者实例并做比较

使用Synchronized

public class SynchronizedConsumerProductDemo {
   
   


    public static void main(String[] args) {
   
   
        ConsumerProduct consumerProduct = new ConsumerProduct();
        new Thread(()->{
   
   
            try {
   
   
                for (int i = 0;i<10;i++){
   
   
                    consumerProduct.consumer();
                }
            } catch (InterruptedException e) {
   
   
                e.printStackTrace();
            }
        },"AAAAAAAAAAA").start();

        new Thread(()->{
   
   
            try {
   
   
                for (int i = 0;i<10;i++){
   
   
                    consumerProduct.product(
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值