java 局部锁,JAVA锁之一(synchronized快速记忆法)

# 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 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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值