当前位置: 首页 > news >正文

synchronized锁与lock锁的区别

引言

在学习多线程时,当时为了解决线程并发问题,曾有两种锁,一种是synchronized同步块,同步方法,一种就是Lock锁,那么这两种锁之间有什么区别?谁更好用呢?

synchronized

同步方法(synchronized)

本质:队列+锁

  • 由于我们可以通过private关键字来保证数据对象只被方法访问,所以只需针对方法提出一套机制,这套机制就是synchronized关键字,它包括两种用法:synchronized方法和synchronized块。

     public synchronized void method(int args){}
  • synchronized方法控制对“对象”的访问,每个对象对应一把锁,每个synchronized方法都必须获得调用该方法的对象的锁才能执行,否则线程会阻塞,方法一旦执行,就会独占该锁,直到该方法返回才释放锁,后面被堵塞的线程才能获得这个锁,继续执行

    缺陷:若将一个大的方法申明为synchronized将会影响效率

弊端

方法里面需要修改的内容才需要锁,锁得太多,浪费资源

同步块
  • 同步块:synchronized(Obj){}

  • Obj称之为 同步监视器

    • obj可以是任何对象,但是推荐使用共享资源作为监视器

    • 同步方法中无需指定监视器,因为同步方法的监视器就是this,就是这个对象本身,或者是class

  • 同步监视器的执行过程

    1. 第一个线程访问,锁定同步监视器,执行其中代码

    2. 第二个线程访问,发现同步监视器被锁定,无法访问

    3. 第一个线程访问完毕,解锁同步监视器

    4. 第二个线程访问,发现同步监视器没有锁,然后锁定并访问

案例展示:

package com.lyc.synchornized;

import java.awt.dnd.DragGestureEvent;

//不安全的取钱
public class UnsafeBank {
    public static void main(String[] args) {
        Account account = new Account(700,"奖学金");
        Bank MIng = new Bank(account,100,"小明");
        Bank Teacher = new Bank(account,50,"老师");
        MIng.start();
        Teacher.start();
    }
}
//账户
class Account{
     int money;
     String name;
    public Account(int money,String name){
        this.money=money;
        this.name=name;
    }

}
//银行:模拟取款
class Bank extends Thread{
    private Account account;//账户
    private int DrawingMoney;//取了多少钱
    private int nowMoney;// 现在手里有多少钱
    public Bank(Account accout,int DrawingMoney,String name){
        super(name);
        this.account = accout;
        this.DrawingMoney = DrawingMoney;
    }
    //取钱
    //synchronized 默认锁的是this
    //所以要使用同步块

    @Override
    public  void run() {
        //锁的对象就是变化的量 需要增删改
        synchronized (account){
            if (account.money<DrawingMoney){
                System.out.println(Thread.currentThread().getName()+"取钱失败,余额不足");
                return;
            }
            //sleep可以放大问题的发生性
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
        //判断有没有钱

        //卡内余额 = 余额-你取的钱
        account.money = account.money - DrawingMoney;
        //你手里的钱
        nowMoney = nowMoney + DrawingMoney;
        System.out.println(account.name+"余额为"+account.money);
        //Thread.currentThread().getName() = this.getName()
        System.out.println(this.getName()+"手里的钱为"+nowMoney);
    }

}

Lock

我们直接去jdk文档中去找

 Lock接口实现类主要分为三类:

ReentrantLock(可重入锁【常用】) , ReentrantReadWriteLock.ReadLock (读锁), ReentrantReadWriteLock.WriteLock(写锁)

我们再去源码中看看:

 发现在ReentrantLock中还有公平锁与非公平锁之分

公平锁:顾名思义,十分公平,讲究先来后到,不能插队

非公平锁:十分不公平:可以插队(默认)

那么如何使用Lock锁呢?

lock三部曲
1.new ReentrantLock()
2.lock.lock();//加锁
3.lock.unlock();//解锁

代码示例:

package com.lyc.demo01;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class SaleTicketDemo02 {
    public static void main(String[] args) {
        //并发:多线程操作同一个资源类,把资源类丢入线程
        Ticket2 ticket = new Ticket2();
        //@FunctionalInterface 函数式接口,jdk1.8新特性 lambda表达式 (参数)->{代码}
        new Thread(() ->
        {for (int i = 0; i < 40; i++)  ticket.sale();},"A").start();
        new Thread(() ->
        {for (int i = 0; i < 40; i++)  ticket.sale();},"B").start();
        new Thread(() ->
        {for (int i = 0; i < 40; i++)  ticket.sale();},"C").start();
        new Thread(() ->
        {for (int i = 0; i < 40; i++)  ticket.sale();},"D").start();

    }
}
//lock三部曲
//1.new ReentrantLock()
//2.lock.lock();//加锁
//3.lock.unlock();//解锁
class Ticket2{
    private int number  = 50;
    //买票的方式
    Lock lock = new ReentrantLock();//可重入锁
    public void sale() {
        lock.lock();//加锁

        try {
            //业务代码
            if (number > 0) {
                System.out.println(Thread.currentThread().getName() + "卖出了" + (number--) + "票,剩余了" + number);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            lock.unlock();//解锁
        }

    }
}

区别(重点)

1.Synchronized是内置的Java关键字,lock是一个Java类

2.Synchronized无法判断锁的状态,Lock可以判断是否获得了锁

3.Synchronized 会自动释放锁(同步块结束就释放了)lock必须手动释放锁,如果不释放锁,就会造成死锁

4.Synchronized 线程1(同步块 阻塞) 线程2(就会一直等待) Lock锁就不会一直等待(try lock()

原因:Lock实现提供了使用synchronized方法和语句的附加功能,通过提供非阻塞尝试来获取锁( tryLock() ),尝试获取可被中断的锁( lockInterruptibly()) ,以及尝试获取可以超时( tryLock(long, TimeUnit) )。

5.Synchronized 可重入锁,不可中断,非公平 Lock ,可重入锁,可以中断,非公平(可以自己设置)

6.Synchronized 适合锁少量的代码同步问题,Lock适合锁大量的同步代码

这就是我总结的两者之间的区别,希望能帮助到大家

http://www.dtcms.com/a/98121.html

相关文章:

  • 实变函数:集合与子集合一例(20250329)
  • JavaFX基础- Button 的基本使用
  • Linux进程管理之子进程的创建(fork函数)、子进程与线程的区别、fork函数的简单使用例子、子进程的典型应用场景
  • 【19期获取股票数据API接口】如何用Python、Java等五种主流语言实例演示获取股票行情api接口之沪深A股实时交易数据及接口API说明文档
  • 参加李继刚线下活动启发:未来提示词还会存在吗?
  • 【初阶数据结构】线性表之双链表
  • 【数电】半导体存储电路
  • 基于Linux平台安装部署Redis全教程
  • 生物化学笔记:医学免疫学原理09 白细胞分化抗原+黏附分子
  • Supplements of My Research Proposal: My Perspectives on the RAG
  • 数据结构:探秘AVL树
  • 【华为OD技术面试真题 - 技术面】- Java面试题(15)
  • Android开发中的数据结构与算法:排序算法
  • TCP协议与wireshark抓包分析
  • 如何封装一个上传文件组件
  • 小河:团队金牌精准计划
  • QML中使用Image显示图片和使用QQuickItem显示图片
  • 告别桌面杂乱与充电焦虑,移速165W百变桌面充电站首发体验
  • Day43 | 129. 求根节点到叶节点数字之和、1382. 将二叉搜索树变平衡、100. 相同的树
  • 循相似之迹:解锁协同过滤的核心推荐逻辑
  • OpenBMC:BmcWeb 生效路由4 将路由添加到Trie中
  • Spring Boot事务管理详解(附银行转账案例)
  • 如何缩短研发周期,降低研发成本?全星APQP软件为您提供解决方案
  • 【Goalng】第九弹-----文件操作、JSON处理
  • 杂草YOLO数据集分享
  • 【AI插件开发】Notepad++插件开发实践:从基础交互到ScintillaCall集成
  • 第十五章:Python的Pandas库详解及常见用法
  • 【云原生】docker 搭建单机PostgreSQL操作详解
  • Pod 网络与 CNI 的作用
  • 结构化分析方法 数据流图详解