传统的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锁是手动的

目录
相关文章
|
7月前
|
安全 Java
Synchronized和Lock的区别
Synchronized和Lock的区别
72 0
|
24天前
Synchronized锁原理和优化
Synchronize是通过对象头的markwordk来表明监视器的,监视器本质是依赖操作系统的互斥锁实现的。操作系统实现线程切换要从用户态切换为核心态,成本很高,此时这种锁叫重量级锁,在JDK1.6以后引入了偏向锁、轻量级锁、重量级锁 偏向锁:当一段代码没有别的线程访问,此时线程去访问会直接获取偏向锁 轻量级锁:当锁是偏向锁时,有另外一个线程来访问,偏向锁会升级为轻量级锁,这个线程会通过自旋方式不断获取锁,不会阻塞,提高性能 重量级锁:轻量级锁自旋一段时间后线程还没有获取到锁,线程就会进入阻塞状态,该锁会升级为重量级锁,重量级锁时,来竞争锁的所有线程都会阻塞,性能降低 注意,锁只能升
25 5
|
安全 Java
一文教你,synchronized和Lock的区别?
最近有多位粉丝被问到synchronized和Lock,据说还是阿里一面的面试题。在分布式开发中,锁是控制线程的重要方式。Java提供了两种锁机制synchronized 和 Lock。接下来,我给大家分享一下我对synchronized和Lock的理解。
216 0
|
Java
synchronized和lock的区别
synchronized和lock的区别
88 0
|
7月前
|
Java C++
11.synchronized底层是怎么通过monitor进行加锁的?
11.synchronized底层是怎么通过monitor进行加锁的?
47 0
11.synchronized底层是怎么通过monitor进行加锁的?
|
Java
Lock 和 Synchronized的区别?
本章主要讲解了Lock 和 Synchronized的区别和知识点
55 0
|
Java
synchronized和Lock的区别
synchronized和Lock的区别
75 0
|
存储 Java
synchronized锁升级原理
synchronized锁升级原理
265 1
synchronized锁升级原理
synchronized和reentrantlock之间的区别
synchronized和reentrantlock之间的区别
【JUC基础】04. Lock锁
java.util.concurrent.locks为锁定和等待条件提供一个框架的接口和类,说白了就是锁所在的包。
5525 0