5. 多线程锁 (公平锁和非公平锁,死锁,可重锁)

news/2024/5/20 8:54:20 标签: 多线程, juc, java, 进程, 线程池

某一个时刻内,只能有唯一 一个线程去访问这些synchronized 方法
所有的静态同步方法用的也是同一把锁——类对象本身,这两把锁是两个不同的对象,所以静态同步方法与非静态同步方法之间是不会有竞态条件的但是一旦一个静态同步方法获取锁后,其他的静态同步方法都必须等待该方法释放锁后才能获取锁,而不管是同一个实例对象的静态同步方法之间,还是不同的实例对象的静态同步方法之间,只要它们同一个类的实例对象

    synchronized 锁的是方法,则是对象锁
    同个对象锁的机制要等待,不同对象锁的机制调用同一个不用等待
    加了static则为class锁而不是对象锁

通过具体的实例进行分析

java">
class Phone {

    public synchronized void sendSMS() throws Exception {
        //停留4秒
        TimeUnit.SECONDS.sleep(4);
        System.out.println("------sendSMS");
    }
    public synchronized void sendEmail() throws Exception {
        System.out.println("------sendEmail");
    }
    public void getHello() {
        System.out.println("------getHello");
    }
}
java">public class Lock_8 {
    public static void main(String[] args) throws Exception {
        Phone phone = new Phone();
        Phone phone2 = new Phone();
        new Thread(() -> {
            try {
                phone.sendSMS();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, "AA").start();
        Thread.sleep(100);
        new Thread(() -> {
            try {
               // phone.sendEmail();
               // phone.getHello();
                phone2.sendEmail();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, "BB").start();
    }
}

 1 标准访问,先打印短信还是邮件
------sendSMS
------sendEmail
2 停4秒在短信方法内,先打印短信还是邮件
------sendSMS
------sendEmail
3 新增普通的hello方法,是先打短信还是hello
------getHello
------sendSMS
4 现在有两部手机,先打印短信还是邮件
------sendEmail
------sendSMS
5 两个静态同步方法,1部手机,先打印短信还是邮件
------sendSMS
------sendEmail
6 两个静态同步方法,2部手机,先打印短信还是邮件
------sendSMS
------sendEmail
7 1个静态同步方法,1个普通同步方法,1部手机,先打印短信还是邮件
------sendEmail
------sendSMS
8 1个静态同步方法,1个普通同步方法,2部手机,先打印短信还是邮件
------sendEmail
------sendSMS

总结:
1.- 同样的对象访问不同的同步锁,是按照顺序执行

    同样的对象访问同步锁与不同步锁,是先不同步锁执行
    不同对象访问不同同步锁,按照顺序执行

2.- 同一对象访问不同静态同步锁,按照顺序执行

    不同对象访问不同静态同步锁,按照顺序执行

3.- 同一对象访问一个静态同步锁,一个同步锁,先执行同步锁

    不同对象访问一个静态同步锁,一个同步锁,先执行同步锁
    即先出同步锁在出静态同步锁

5.1 公平锁和非公平锁

  • 公平锁:效率相对低 (但是cpu 的利用高了)
  • 非公平锁:效率高,但是线程容易饿死(所有的工作,有一个线程完成)

通过查看源码
带有参数的ReentrantLock(true)公平锁
ReentrantLock(false)非公平锁
主要是调用NonfairSync()FairSync()

5.2 可重入锁

synchronized和lock都是可重入锁

  • sychronized是隐式锁,不用手工上锁与解锁,而lock为显示锁,需要手工上锁与解锁
  • 可重入锁也叫递归锁

而且有了可重入锁之后,破解第一把之后就可以一直进入到内层结构

嵌套实现代码 他能进入下一个锁内

5.3 死锁

两个或以上的进程因为争夺资源而造成互相等待资源的现象称为死锁
在这里插入图片描述
产生死锁的原因:

  1. 系统资源不足
  2. 系统资源分配不当
  3. 进程运行顺序不当

我们有时候不知道是否是死锁  。那么怎么来验证呢? (电脑配置的有环境变量,在命令窗口)

  1.  jps 类似于linux中的 ps -ef 查看进程
  2. jstack 自带的堆栈跟踪工具

 

 具体死锁的操作代码实列
可理解背下来,大厂面试可考,死锁的简单案例

java">public class DeadLock {

    //创建两个对象
    static Object a = new Object();
    static Object b = new Object();

    public static void main(String[] args) {
        new Thread(()->{
            synchronized (a) {
                System.out.println(Thread.currentThread().getName()+" 持有锁a,试图获取锁b");
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (b) {
                    System.out.println(Thread.currentThread().getName()+" 获取锁b");
                }
            }
        },"A").start();

        new Thread(()->{
            synchronized (b) {
                System.out.println(Thread.currentThread().getName()+" 持有锁b,试图获取锁a");
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (a) {
                    System.out.println(Thread.currentThread().getName()+" 获取锁a");
                }
            }
        },"B").start();
    }
}


http://www.niftyadmin.cn/n/1712928.html

相关文章

JUC高并发编程的学习,知识点详细概括

JUC 的概述 https://blog.csdn.net/qq_52252193/article/details/121903199 一.Lock 接口的概述 1. Lock (锁的)接口_想成为大神说32的博客-CSDN博客 二.线程间的通信 (Sysnchronized. Lock,的案例) 2.什么是线程间的通信 ?怎么实…

二叉树的三种遍历算法的实现(前序、中序、后序)递归与非递归

二叉树的三种遍历算法的实现(前序、中序、后序)递归与非递归 1、二叉树的定义 二叉树是n(n>0)个数据元素的有限集,含有唯一的称为根的元素,且,其余元素分成两个互不相交的子集,…

6. Callable接口

创建线程的多种方式: 继承Thread类实现Runnable接口Callable接口线程池 目前学习了有两种创建线程的方法,一种是通过创建 Thread 类,另一种是通过使用 Runnable 创建线程,但是,Runnable 缺少的一项功能是,…

数组和指针的几点理解

数组和指针的理解 1.1数组 1.1.1、数组定义 一组具有同名的同属性的数据就组成了一个数组(array) 由此可以知道: 1、数组是一组有序数据集合。数组中个数据的排列具有一定的规律,下标代表数据在数组中的序号。 int a[10];方括…

7. JUC强大辅助类(减少计数CountDownLatch,循环栅栏CyclicBarrier,信号灯Semaphore)便于解决并发功能

该辅助类主要讲述三个减少计数CountDownLatch 循环栅栏 CyclicBarrier 信号灯Semaphore 7.1 CountDownLatch 该类的构造方法为 CountDownLatch(int count)构造一个用给定计数初始化的CountDownLatch在这里插入代码片 两个常用的主要方法await() 使当前线程在锁存器倒计数至…

队列的数组表示

1、队列的结构特点和操作 复习一下队列:数据结构“队列”与我们日常生活中的排队非常相似,按照先到先办的原则办事,并且严格规定不能加塞,也不允许中途离队。 队列:限定只能在队尾进行插入元素,在表头进行…

8. 读写锁

回顾悲观锁和乐观锁的概念悲观锁: 见字知意,他是干什么都很悲观,所以在操作的时候,每次都上锁,使用时解锁乐观锁:他很乐观,多线程,并不上锁,但是会发生 线程安全问题 表…

字符数组与字符指针的理解

1、字符数组 先来想一想什么是字符串: 字符串(character string)是一个或多个字符的序列,如下所示: “I am a good boy ”双引号不是字符串的一部分。双引号仅告知编译器它括起来的是字符串,正如单引号用于…