JAVA锁之一(synchronized快速记忆法)

栏目: Java · 发布时间: 5年前

内容简介:在JAVA中有很多锁,都可以实现多线程编程中实现数据的锁定,防止并发问题,本章节主要简单介绍下

# JAVA锁之一(synchronized快速记忆法)

一· 概述

JAVA 中有很多锁,都可以实现多线程编程中实现数据的锁定,防止并发问题,本章节主要简单介绍下 synchronized .

二· 介绍

2.1 修饰场景

synchronized 是用于修饰用的加锁关键词,可以用于方法和代码块中,可以简单理解为锁住对象对应的指针地址,只要区分好指针对象是否同一个地址,就可以判断两个线程的锁是否互斥。

synchronized 是可重入的,意思就是当前线程获得锁之后,其他线程就无法获得锁进入,但是当前线程自己还可以再次获得锁多次进入。

由于使用比较简单,下面就简单列举一张表格,表示锁的应用场景以及说明。

修饰对象 被锁住对象 是否全局唯一 简单例子
类的类型 类的类型 synchronized(Example.class) {...} , 全局锁,其他线程无法进入
类的实例 类的实例 × synchronized(this){...} 或者
final A a = new A()
synchronized(a){...}
普通成员函数 类的实例 × public synchronized void f() {...} 锁住类的实例
静态成员函数 类的类型 public static synchronized void f() {...} 锁住类的类型
(静态)成员变量 成员对象所指向的实例,一定要用final修饰,不然重新赋值后就不是同一个对象了 ×
final (static) A a = new A()
synchronized(a){...}

快速记忆法:可以简单理解成锁住对象是对象指针值。

2.2 代码样例

以下的代码,请观察哪些是互斥的

// http://www.easysb.cn/2019/05/341.html

public class LockTest {
    @Getter
    private final A a = new A();

    private static int TICK = 5;

    public void bFun1() {
        synchronized (a) {
            int count = 0;
            while (count++ < TICK) {
                System.out.println("hello from LockTest::bFun1");
                ThreadUtils.sleepQuitely(1000);
            }
        }
    }

    public void bFun2() {
        synchronized (a.getClass()) {
            int count = 0;
            while (count++ < TICK) {
                System.out.println("hello from LockTest::bFun2");
                ThreadUtils.sleepQuitely(1000);
            }
        }
    }

    @Data
    public static class A {
        private final Object a = new Object();

        private synchronized void aFun1() {
            int count = 0;
            while (count++ < TICK) {
                System.out.println("hello from A::aFun1");
                ThreadUtils.sleepQuitely(1000);
            }
        }

        private void aFun2() {
            synchronized(this) {
                int count = 0;
                while (count++ < TICK) {
                    System.out.println("hello from A::aFun2");
                    ThreadUtils.sleepQuitely(1000);
                }
            }
        }

        private synchronized static void aFun3() {
            int count = 0;
            while (count++ < TICK) {
                System.out.println("hello from A::aFun3");
                ThreadUtils.sleepQuitely(1000);
            }
        }
        private synchronized static void aFun4() {
            synchronized (A.class) {
                int count = 0;
                while (count++ < TICK) {
                    System.out.println("hello from A::aFun4");
                    ThreadUtils.sleepQuitely(1000);
                }
            }
        }
    }

    public static void main(String[] args) {
        LockTest t = new LockTest();
        List<Thread> list = Lists.newArrayList();
        list.add(new Thread(() -> {
            t.bFun1();
        }));
        list.add(new Thread(() -> {
            t.bFun2();
        }));
        list.add(new Thread(() -> {
            t.getA().aFun1();
        }));
        list.add(new Thread(() -> {
            t.getA().aFun2();
        }));
        list.add(new Thread(() -> {
            t.getA().aFun3();
        }));
        list.add(new Thread(() -> {
            t.getA().aFun4();
        }));
        for (Thread thread : list) {
            thread.start();
        }
        ThreadUtils.sleepQuitely(1000 * 30);
    }
}

按照上面地址的快速记忆理解方案,那么可以简单归纳如下:

  • LockTest::bFun1 锁住的对象是成员变量 a 地址。
  • LockTest::bFun2 锁住的对象是A的类对象 a.getClass() ,也就是 A.class 地址,是全局唯一的。
  • A::aFun1 修饰普通成员函数,锁住类对象实例的地址,也就是 a 地址。
  • A::aFun2 普通成员函数 this ,锁住类对象实例的地址,也就是 a 地址。
  • A::aFun3 静态成员函数,锁住A的类对象,也就是 A.class 地址。
  • A::aFun4 成员函数,锁住类对象实例的地址 A.class ,全局唯一。

从上可以看出互斥的方法如下:

  • 实例 a 地址: LockTest::bFun1 , A::aFun1 , A::aFun2
  • 类对象 A.class 地址: LockTest::bFun2 , A::aFun3 , A::aFun4

输出的结果可能有多种,以下是一种输出结果

hello from LockTest::bFun2
hello from LockTest::bFun1
hello from LockTest::bFun2
hello from LockTest::bFun1
hello from LockTest::bFun2
hello from LockTest::bFun1
hello from LockTest::bFun2
hello from LockTest::bFun1
hello from LockTest::bFun1
hello from LockTest::bFun2
hello from A::aFun2
hello from A::aFun4
hello from A::aFun4
hello from A::aFun2
hello from A::aFun4
hello from A::aFun2
hello from A::aFun2
hello from A::aFun4
hello from A::aFun4
hello from A::aFun2
hello from A::aFun1
hello from A::aFun3
hello from A::aFun1
hello from A::aFun3
hello from A::aFun3
hello from A::aFun1
hello from A::aFun3
hello from A::aFun1
hello from A::aFun1
hello from A::aFun3

以上所述就是小编给大家介绍的《JAVA锁之一(synchronized快速记忆法)》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

营销三大算法

营销三大算法

刘学林、刘逸春、张新春、王颖、余彬晶、刘锦炽、董少灵、沈逸超、王锐睿、孙静若 / 上海交通大学出版社 / 2018-1-31 / 88.00元

未来的营销应该是数字化的,即数字营销。以数据为本,用演算做根,数字营销能够演算生活的方方面面。在数字营销领域,市场的整个投入、产出带来什么东西?企业一定要狠清楚地知道,这是做数字营销的本质。数字营销和企业做生意的本质是一样的,目的都是以投入换取产出。 本书由正和岛数字营销部落编写,基于大量企业的案例与数据,提出了营销三大核心算法与一套全局营销系统,帮助企业CEO与营销人员科学化建立全局营销系......一起来看看 《营销三大算法》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

html转js在线工具
html转js在线工具

html转js在线工具