传统的synchronized和Lock

简介: 传统的synchronized和Lock

传统的synchronized锁

并发操作(多线程操作同一个资源),正常代码

synchronized修饰同步代码块默认锁的是this,也可以是具体类的class(Ticket.class)


package com.wyh.demo;
/**
 * @program: JUC
 * @description: 卖票 使用synchronized修饰方法或者代码块使得线程安全
 * @author: 魏一鹤
 * @createDate: 2022-02-11 22:31
 **/
//真正的多线程开发,公司中的开发,降低耦合性
//线程就是一个单独的资源类,没有任何附属的操作
//1 属性 2 方法
public class saleTicketDemo01 {
public static void main(String[] args){
//资源类
       Ticket ticket=new Ticket();
//多线程操作买票 并发:多个线程操作多个资源类,把资源类丢入线程就可以了
       //FunctionalInterface 函数式接口 jdk1.8 lambda表达式 (参数)->{代码}
       new Thread(()->{
for (int i = 0; i < 10; i++) {
//调用卖票方法
               ticket.sale();
           }
           },"线程A").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
//调用卖票方法
               ticket.sale();
           }
       },"线程B").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
//调用卖票方法
               ticket.sale();
           }
       },"线程C").start();
   }
}
//资源类 OOP编程
class Ticket {
//属性 方法
    //票数
    private int ticketNums=10;
//卖票方法
    public void sale(){
//如果票数大于0就可以正常卖票
        if(ticketNums > 0){
            System.out.println(Thread.currentThread().getName() + "买到了"+ticketNums--+"张票"+"剩余:"+ticketNums+"张票");
        }
    }
}


通过控制台可以发现结果很混乱不是我们想要的 CPU的调度很混乱,资源被乱抢


image.png


线程A买到了10张票剩余:9张票

线程B买到了9张票剩余:8张票

线程A买到了8张票剩余:7张票

线程A买到了6张票剩余:5张票

线程B买到了7张票剩余:6张票

线程B买到了4张票剩余:3张票

线程B买到了3张票剩余:2张票

线程B买到了2张票剩余:1张票

线程B买到了1张票剩余:0张票

线程A买到了5张票剩余:4张票


被synchronized修饰方法和代码块 代码如下


class Ticket {
//修饰方法
//synchronized本质就是队列,锁(排队)
public synchronized void sale(){
//如果票数大于0就可以正常卖票
    if(ticketNums > 0){
        System.out.println(Thread.currentThread().getName() + "买到了"+ticketNums--+"张票"+"剩余:"+ticketNums+"张票");
    }
}
//synchronized本质就是队列,锁(排队)
//修饰代码块对象为this
public  void sale(){
    //默认对象是this
synchronized (this){
//如果票数大于0就可以正常卖票
        if(ticketNums > 0){
            System.out.println(Thread.currentThread().getName() + "买到了"+ticketNums--+"张票"+"剩余:"+ticketNums+"张票");
        }
    }
}
//synchronized本质就是队列,锁(排队)
//修饰代码块对象为类
public  void sale(){
    //默认对象是this
synchronized (Ticket.class){
//如果票数大于0就可以正常卖票
        if(ticketNums > 0){
            System.out.println(Thread.currentThread().getName() + "买到了"+ticketNums--+"张票"+"剩余:"+ticketNums+"张票");
        }
    }
 }
}


再次运行发现结果是我们想要的,CPU调度井井有序,像是被排队一样


image.png


线程A买到了10张票剩余:9张票

线程A买到了9张票剩余:8张票

线程A买到了8张票剩余:7张票

线程A买到了7张票剩余:6张票

线程A买到了6张票剩余:5张票

线程A买到了5张票剩余:4张票

线程A买到了4张票剩余:3张票

线程A买到了3张票剩余:2张票

线程A买到了2张票剩余:1张票

线程A买到了1张票剩余:0张票

lock锁

加锁:lock()  解锁:unLock();

lock锁属于JUC下的接口 它的实现类有ReentrantLock(可重入锁,最常用的),ReadLock(读锁),WriterLock(写锁)


image.png


观察ReentrantLock源码可以发现 它有一个构造方法(如果传参根据传的参数决定公平或者不公平锁,不传参的话默认是不公平锁) 可以传一个boolean值,如果为true的话是一个公平锁,如果为false的话是一个非公平锁


image.png


那么什么是公平锁和非公平锁呢?

  1. 公平锁(Fairsync )

十分公平,先来后到,根据线程安排调度

  1. 非公平锁(NonFairsync)

十分不公平,.可以插队(默认是非公平锁 ),根据CPU调度

其实就是锁的执行调度不同,比如有一个3h的线程有一个3s多线程,如果3h排在了3s之前,就会很不公平,所以java默认是不公平锁,synchronized也是如此

注意:lock一般结合try catch finally代码块使用 业务代码写在try中,解锁(unLock())写在finally中

synchronized是全自动的,lock是手动的



使用lock三部曲

  1. Lock lock=new ReentrantLock(); 可重入锁ReentrantLock类
  2. 加锁 lock.lock()
  3. 解锁 lock.unLock()
package com.wyh.demo;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
 * @program: JUC
 * @description: 卖票 使用lock锁使得线程变得安全
 * @author: 魏一鹤
 * @createDate: 2022-02-11 22:31
 **/
//真正的多线程开发,公司中的开发,降低耦合性
//线程就是一个单独的资源类,没有任何附属的操作
//1 属性 2 方法
public class saleTicketDemo02 {
public static void main(String[] args){
//资源类
       Ticket2 ticket=new Ticket2();
//多线程操作买票 并发:多个线程操作同一个资源类,把资源类丢入线程就可以了
       //FunctionalInterface 函数式接口 jdk1.8 lambda表达式 (参数)->{代码}
       //for循环只有一句的时候 可以简化"{}"
       new Thread(()->{ for (int i = 0; i < 10; i++) ticket.sale(); },"线程A").start();
new Thread(()->{ for (int i = 0; i < 10; i++) ticket.sale(); },"线程B").start();
new Thread(()->{ for (int i = 0; i < 10; i++) ticket.sale(); },"线程C").start();
   }
}
//资源类 OOP编程 使用lock锁
class Ticket2 {
//属性 方法
    //票数
    private int ticketNums=10;
//lock是一个接口 创建它的实现类 可重入锁ReentrantLock实现类
    //synchronized是全自动的,lock是手动的
    //lock三部曲
    //1 Lock lock=new ReentrantLock(); 可重入锁ReentrantLock类
    //2 加锁 lock.lock()
    //3 解锁 lock.unLock()
    Lock lock=new ReentrantLock();
//卖票方法
    public  void sale() {
//注意 lock一般结合try catch finally代码块使用
        //加锁
        lock.lock();
try {
//业务代码写在try中
            //如果票数大于0就可以正常卖票
            if (ticketNums > 0) {
                System.out.println(Thread.currentThread().getName() + "买到了" + ticketNums-- + "张票" + "剩余:" + ticketNums + "张票");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
//解锁一定在finally中
            //解锁
            lock.unlock();
        }
    }
}


运行代码通过console控制台发现,效果和synchronized是一样的,不同的是synronzied是全自动的,lock锁是手动的

目录
相关文章
|
存储 数据安全/隐私保护
音乐宿主软件有哪些?哪个最好用?FL Studio/Cubase/Studio one
现如今市面上的音乐宿主软件有很多,同时每个音乐宿主软件都有其优缺点,选择哪款音乐宿主软件,就成了新入门小伙伴面临的一个难题,所以今天和大家分享一下,音乐宿主软件对比,音乐宿主软件需要什么配置。
6508 0
|
12月前
|
安全 Android开发 iOS开发
Android vs. iOS:构建生态差异与技术较量的深度剖析###
本文深入探讨了Android与iOS两大移动操作系统在构建生态系统上的差异,揭示了它们各自的技术优势及面临的挑战。通过对比分析两者的开放性、用户体验、安全性及市场策略,本文旨在揭示这些差异如何塑造了当今智能手机市场的竞争格局,为开发者和用户提供决策参考。 ###
|
Python
Python软件包及环境管理器conda实战篇
详细介绍了如何使用conda进行Python软件包管理及环境管理,包括查看、安装、卸载软件包,切换源,管理不同版本的Python环境,以及解决使用过程中可能遇到的错误。
506 2
Python软件包及环境管理器conda实战篇
|
存储 缓存 安全
动态DMA映射指南 【ChatGPT】
动态DMA映射指南 【ChatGPT】
|
机器学习/深度学习 人工智能 自然语言处理
揭秘In-Context Learning(ICL):大型语言模型如何通过上下文学习实现少样本高效推理[示例设计、ICL机制详解]
揭秘In-Context Learning(ICL):大型语言模型如何通过上下文学习实现少样本高效推理[示例设计、ICL机制详解]
揭秘In-Context Learning(ICL):大型语言模型如何通过上下文学习实现少样本高效推理[示例设计、ICL机制详解]
|
监控 数据挖掘 关系型数据库
结构化思维的理解与思考
结构化思维是一种将信息要素从无效转化为有序,提炼核心要点,将信息转化为有结构的知识,更好的帮助大脑理解和记忆,并支持我们清晰表达的通用能力。
1488 2
结构化思维的理解与思考
|
前端开发 安全 区块链
前沿技术探索:Web3.0与前端开发的融合之路
【2月更文挑战第12天】 在数字技术快速发展的今天,Web3.0作为互联网的新阶段,不仅预示着去中心化、更加智能化的网络环境,还为前端开发带来了前所未有的挑战与机遇。本文将深入探讨Web3.0对前端开发的影响,分析其在实际应用中如何与前端技术融合,以及前端开发者如何适应这一变革,把握新时代的技术趋势。通过案例分析与技术展望,我们将一窥Web3.0与前端开发融合的未来图景,为前端开发者提供新的思考和行动指南。
525 26
|
网络协议 安全 网络安全
【专栏】IPv6是为解决IPv4地址不足、安全性和配置复杂性问题而提出的下一代互联网协议
【4月更文挑战第28天】IPv6是为解决IPv4地址不足、安全性和配置复杂性问题而提出的下一代互联网协议。它提供128位地址空间(几乎无限)、简化报文格式、内置IPsec安全机制、自动配置能力及增强的QoS。IPv6的优势包括更高的传输效率、更强的安全性、移动性和组播功能,以及即插即用的设备。然而,部署面临IPv4兼容性、技术更新、经济驱动和安全挑战。随着技术发展,IPv6的普及将成为必然趋势。
896 1
|
安全 Android开发 开发者
安卓手机系统的优势和劣势分析
【2月更文挑战第8天】 安卓(Android)是目前全球最流行的移动操作系统之一,拥有强大的开源技术和丰富的应用生态系统。本文将从多个维度对安卓系统进行分析,并探讨其优势和劣势。
1630 2
|
运维 监控 Java
Java在运维领域的技术应用与实践
Java在运维领域的技术应用与实践
214 1