JUC并发编程学习笔记(四)8锁现象

这篇具有很好参考价值的文章主要介绍了JUC并发编程学习笔记(四)8锁现象。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

8锁现象

八锁->就是关于锁的八个问题

锁是什么,如何判断锁的是谁

对象、class模板

深刻理解锁

锁的东西无外乎就两样:1、同步方法的调用者,2、Class模板。

同一个锁中,只有当前线程资源释放后才会被下一个线程所接手。

同步方法的调用者是两个不同的实例时,互不相关。

静态同步方法(static)锁的是整个Class模板,和同步方法的调用者也不是同一个锁;切Class模板在Java程序中唯一。

代码示例

1、浅浅理解锁的作用

同一把锁中根据执行先后释放资源,保证一个资源的使用顺序

package org.example.phone;

import java.util.concurrent.TimeUnit;

public class Test1 {
    public static void main(String[] args) {
//        标准情况下,打印顺序为 1、发短信,2、打电话
//        给sendMsg内部延迟四秒执行,执行顺序依旧是 1、发短信,2、打电话
//        可知,并非是我们所想的,A线程在前面就先执行,而是锁的机制导致了这种情况
//        phone1只创建了一个对象,所以这个对象的锁只有一把,谁先拿到就是谁先执行
//        锁的对象是该方法的调用者,即phone1
        Phone1 phone1 = new Phone1();
        new Thread(()->{
            phone1.sendMsg();
        },"A").start();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        new Thread(()->{
            phone1.call();
        },"B").start();
    }
}
class Phone1{
//    synchronized锁的对象是方法的调用者,Phone1只new了一个对象,所以锁的是new出来的整个对象
    public synchronized void sendMsg(){

        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println("发短信");
    }
    public synchronized void call(){
        System.out.println("打电话");
    }
}

2、区分锁的对象

不同的实例使用的锁并非同一把,所以也无法同时锁定某个固定的资源、无法对同一资源进行有顺序的操作

package org.example.phone;

import java.util.concurrent.TimeUnit;

public class Test3 {
    public static void main(String[] args) {
//        标准情况下,打印顺序为 1、发短信,2、打电话
//        给sendMsg内部延迟四秒执行,执行顺序依旧是 1、发短信,2、打电话
//        可知,并非是我们所想的,A线程在前面就先执行,而是锁的机制导致了这种情况
//        phone1只创建了一个对象,所以这个对象的锁只有一把,谁先拿到就是谁先执行
//        锁的对象是该方法的调用者,即phone1

//        调用两个不同对象的方法,锁的是两个不同的对象,此时先出现打电话,说明不同对象之间的锁互不影响
        Phone3 phone3_1 = new Phone3();
        Phone3 phone3_2 = new Phone3();
        new Thread(()->{
            phone3_1.sendMsg();
        },"A").start();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        new Thread(()->{
            phone3_2.call();
        },"B").start();
    }
}
class Phone3{
    //    synchronized锁的对象是方法的调用者,Phone1只new了一个对象,所以锁的是new出来的整个对象
    public synchronized void sendMsg(){

        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println("发短信");
    }
    public synchronized void call(){
        System.out.println("打电话");
    }
    //    当在资源类中添加了一个普通方法后,先输出hello
//    没有锁,不是同步方法,不受锁的影响
    public void hello(){
        System.out.println("Hello");
    }
}

3、了解锁的参与者

只有同步方法参与锁,普通方法依旧按照java执行顺序执行

package org.example.phone;

import java.util.concurrent.TimeUnit;

public class Test2 {
    public static void main(String[] args) {
//        标准情况下,打印顺序为 1、发短信,2、打电话
//        给sendMsg内部延迟四秒执行,执行顺序依旧是 1、发短信,2、打电话
//        可知,并非是我们所想的,A线程在前面就先执行,而是锁的机制导致了这种情况
//        phone1只创建了一个对象,所以这个对象的锁只有一把,谁先拿到就是谁先执行
//        锁的对象是该方法的调用者,即phone1
        Phone2 phone2 = new Phone2();
        new Thread(()->{
            phone2.sendMsg();
        },"A").start();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        new Thread(()->{
            phone2.hello();
        },"B").start();
    }
}
class Phone2{
    //    synchronized锁的对象是方法的调用者,Phone1只new了一个对象,所以锁的是new出来的整个对象
    public synchronized void sendMsg(){

        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println("发短信");
    }
    public synchronized void call(){
        System.out.println("打电话");
    }
//    当在资源类中添加了一个普通方法后,先输出hello
//    没有锁,不是同步方法,不受锁的影响
    public void hello(){
        System.out.println("Hello");
    }
}

4、明白锁能锁谁

锁只能锁两个东西,一个是同步方法的调用者,一个是整个Class模板(全局唯一),一旦使用static创建静态同步方法,那么该方法的锁锁的就是全局唯一的Class模板,并且在反射时就已经被创建了

package org.example.phone;

import java.util.concurrent.TimeUnit;

public class Test4 {
    public static void main(String[] args) {
//        两个对象的Class类模板只有一个;static,锁的是Class
        Phone4 phone4_1 = new Phone4();
        Phone4 phone4_2 = new Phone4();
        new Thread(()->{
            phone4_1.sendMsg();
        },"A").start();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        new Thread(()->{
            phone4_2.call();
        },"B").start();
    }
}
class Phone4{
//    synchronized锁的对象是方法的调用者
//    注:增加了static静态方法 此时调用该方法的就变成了Phone4的反射对象,全局唯一
//    此时锁的就是Class模板了,即不管你有几个调用者,都在同一个锁
//    static方法类一加载就有了!锁的是Class
    public static synchronized void sendMsg(){

        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println("发短信");
    }
    public static synchronized void call(){
        System.out.println("打电话");
    }
}

5、深入理解锁的是谁

静态同步方法和普通同步方法在一起使用时,锁的并非同一对象,所以打印顺序也时按java的执行顺序来,并不存在锁定资源的情况文章来源地址https://www.toymoban.com/news/detail-739976.html

package org.example.phone;

import java.util.concurrent.TimeUnit;
/*
* 1、一个静态同步方法,一个普通同步方法,先打印发短信还是打电话
*   两个方法一个锁的是Class模板,一个锁的是调用者,锁的不是同一对象,所以延迟四秒的静态同步方法后打印,延迟一秒的普通同步方法先打印
*
* */
public class Test5 {
    public static void main(String[] args) {

        Phone5 phone5_1 = new Phone5();
//        Phone5 phone5_2 = new Phone5();
        new Thread(()->{
            phone5_1.sendMsg();
        },"A").start();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        new Thread(()->{
            phone5_1.call();
        },"B").start();
    }
}
class Phone5{
//    锁的是Class模板
    public static synchronized void sendMsg(){

        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println("发短信");
    }
//    锁的是调用者
    public synchronized void call(){
        System.out.println("打电话");
    }
}

到了这里,关于JUC并发编程学习笔记(四)8锁现象的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • JUC并发编程学习笔记(八)读写锁

    JUC并发编程学习笔记(八)读写锁

    ReadWriteLock ReadWriteLock只存在一个实现类那就是ReentrantReadWriteLock,他可以对锁实现更加细粒化的控制 读的时候可以有多个阅读器线程同时参与,写的时候只希望写入线程是独占的 Demo:

    2024年02月06日
    浏览(15)
  • JUC并发编程学习笔记(十四)异步回调

    JUC并发编程学习笔记(十四)异步回调

    Future设计的初衷:对将来的某个事件的结果进行建模 在Future类的子类中可以找到CompletableFuture,在介绍中可以看到这是为非异步的请求使用一些异步的方法来处理 点进具体实现类中,查看方法,可以看到CompletableFuture中的异步内部类,里面是实现的异步方法 以及一些异步方法

    2024年02月05日
    浏览(13)
  • JUC并发编程学习笔记(六)Callable(简单)

    JUC并发编程学习笔记(六)Callable(简单)

    callable接口和runnable接口类似,都是为了执行另外一条线程而设计的,区别是Runnable不会返回结果也不会抛出异常。 1、可以有返回值 2、可以抛出异常 3、方法不同;run()/call(); Runnable 实现Runnable接口,重写run方法,无返回值 Callable 实现Callable接口,重写call方法,有返回值,可

    2024年02月06日
    浏览(14)
  • JUC并发编程学习笔记(十)线程池(重点)

    JUC并发编程学习笔记(十)线程池(重点)

    线程池:三大方法、七大参数、四种拒绝策略 池化技术 程序的运行,本质:占用系统的资源!优化资源的使用!- 池化技术(线程池、连接池、对象池......);创建和销毁十分消耗资源 池化技术:事先准备好一些资源,有人要用就拿,拿完用完还给我。 线程池的好处: 1、

    2024年02月06日
    浏览(18)
  • JUC并发编程学习笔记(十二)Stream流式计算

    JUC并发编程学习笔记(十二)Stream流式计算

    什么是Stream流式计算 大数据:存储+计算 集合、MySql这些的本质都是存储东西的; 计算都应该交给流来操作! 一个案例说明:函数式接口、lambda表达式、链式编程、Stream流式计算

    2024年02月05日
    浏览(15)
  • JUC并发编程学习笔记(十八)深入理解CAS

    JUC并发编程学习笔记(十八)深入理解CAS

    什么是CAS 为什么要学CAS:大厂你必须深入研究底层!有所突破! java层面的cas-------compareAndSet compareAndSet(int expectedValue, int newValue) 期望并更新,达到期望值就更新、否则就不更新! Unsafe类 java不能直接操作内存,但是可以调用c++,c++可以操作内存,java可以通过native定义

    2024年02月05日
    浏览(18)
  • JUC并发编程学习笔记(二)Lock锁(重点)

    JUC并发编程学习笔记(二)Lock锁(重点)

    传统的synchronized 传统的解决多线程并发导致的一些问题我们会使用synchronized来解决,synchronized的本质就是队列、锁。 Lock的实现类有:可重复锁(最常用)、读锁、写锁 在创建可重复锁时,可传入boolean类型值来决定该锁是公平锁(先来后到)还是非公平锁(可插队)

    2024年02月06日
    浏览(11)
  • JUC并发编程学习笔记(七)常用的辅助类

    JUC并发编程学习笔记(七)常用的辅助类

    CountDownLatch 这是一个JUC计数器辅助类,计数器有加有减,这是减。 使用方法 使用前 可能会在所有人没出去之前关门 使用后 不在乎谁先出去,但是一定要总数等于0后才会关门 原理 countDownLatch.countDown();//总数减1 countDownLatch.await();//等待总数变为0才会往下执行,相当于阻塞当

    2024年02月06日
    浏览(12)
  • JUC并发编程学习笔记(一)认知进程和线程

    进程 一个程序,如QQ.exe,是程序的集合 一个进程往往可以包含多个线程,至少包含一个 java默认有两个线程,GC垃圾回收线程和Main线程 线程:一个进程中的各个功能 java无法真正的开启线程,因为java是运行在虚拟机上的,所以只能通过C++,通过native本地方法调用C++开启线程

    2024年02月06日
    浏览(47)
  • JUC并发编程学习笔记(十七)彻底玩转单例模式

    JUC并发编程学习笔记(十七)彻底玩转单例模式

    单例中最重要的思想-------构造器私有! 恶汉式、懒汉式(DCL懒汉式!) 恶汉式 懒汉式 DCL懒汉式 完整的双重检测锁模式的单例、懒汉式、DCL懒汉式 但是有反射!只要有反射,任何的代码都不安全,任何的私有都是摆设 正常的单例模式: 反射破坏单例: 怎么去解决这

    2024年02月05日
    浏览(12)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包