Java学习笔记Spring-BootJava 杂谈

一张图讲解对象锁和关键字synchronized修饰方法(代码块

2019-04-22  本文已影响19人  4bfeaf8c2970

做一个积极的人

编码、改bug、提升自己

我有一个乐园,面向编程,春暖花开!

每个对象在出生的时候就有一把钥匙(监视器Monitor),那么被synchronized 修饰的方法相当于给方法加了一个锁,这个方法就可以进行同步,在多线程的时候,不会出现线程安全问题。

注:Monitor是 Java中用以实现线程之间的互斥与协作的主要手段,它可以看成是对象或者 Class的锁。每一个对象都有,也仅有一个 Monitor。

下面通过一张图片进行讲解:

一、请看图片

图片看不清,请点击这里 :高清大图

二、图片对应的代码

import java.util.Date;

/**

* 测试的object类

*

* @author:dufy

* @version:1.0.0

* @date 2017/9/29

* @email 742981086@qq.com

*/

public class ObjectTest {

public synchronized void methodA(){

try {

System.out.println("This is methodA ...." + Thread.currentThread().getName() + ": " + new Date());

Thread.sleep(1000);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

public void methodB(){

System.out.println("This is methodB ...." + Thread.currentThread().getName() + ": " + new Date());

}

public synchronized void methodC(){

try {

System.out.println("This is methodC ...." + Thread.currentThread().getName() + ": " + new Date());

Thread.sleep(3000);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

复制代码

package com.dufy.concurrentcode;

/**

* 测试线程类

*

* @author:dufy

* @version:1.0.0

* @date 2017/9/29

* @email 742981086@qq.com

*/

public class ThreadTest extends Thread{

public static void main(String[] args) {

ObjectTest ot = new ObjectTest();

Thread1 t1 = new Thread1(ot,"thread1");

Thread2 t2 = new Thread2(ot,"thread2");

Thread3 t3 = new Thread3(ot,"thread3");

Thread4 t4 = new Thread4(ot,"thread4");

t1.start();

t2.start();

t3.start();

t4.start();

}

static class Thread1 extends Thread{

private ObjectTest objectTest;

public Thread1(ObjectTest objectTest,String name){

setName(name);

this.objectTest = objectTest;

}

@Override

public void run() {

super.run();

objectTest.methodA();

}

}

static class Thread2 extends Thread{

private ObjectTest objectTest;

public Thread2(ObjectTest objectTest,String name){

setName(name);

this.objectTest = objectTest;

}

@Override

public void run() {

super.run();

objectTest.methodB();

}

}

static class Thread3 extends Thread{

private ObjectTest objectTest;

public Thread3(ObjectTest objectTest,String name){

setName(name);

this.objectTest = objectTest;

}

@Override

public void run() {

super.run();

objectTest.methodA();

}

}

static class Thread4 extends Thread{

private ObjectTest objectTest;

public Thread4(ObjectTest objectTest,String name){

setName(name);

this.objectTest = objectTest;

}

@Override

public void run() {

super.run();

objectTest.methodC();

}

}

}

复制代码

运行结果:

This is methodB ....thread2: Fri Sep 29 23:21:17 CST 2017

This is methodA ....thread1: Fri Sep 29 23:21:17 CST 2017

This is methodC ....thread4: Fri Sep 29 23:21:18 CST 2017

This is methodA ....thread3: Fri Sep 29 23:21:21 CST 2017

复制代码

注: 1、运行的结果可能和上图讲的线程流程不同,没有关系,只要理解对象锁和synchronized的核心思想就好,线程的运行本来就是具有随机性这个特点。2、此段代码是同步方法,其实同步的代码块也是一个道理,同步代码块用synchronized(this)时候,当一个线程访问object的一个synchronized(this)同步代码块的时候,其他线程对object中所有其他的synchronized(this)同步的代码块访问都被阻塞(阻塞的是同步代码块,线程依然可以进入同步代码块的方法)。

三、总结说明

每个对象都有一把锁(对象监视器),关键字synchronized取得锁都是对象锁,而不是把一段代码或方法(函数)当做锁。

上图所示,哪个线程先执行带有synchronized关键字的方法,哪个线程就持有这个方法所属对象的钥匙。其他线程只能处于等待状态。

调用关键字synchronized声明的方法,一定是排队运行的。这才是使用synchronized关键字的作用,排队运行,如果有共享资源的话,那么共享资源的读取就是线程安全的。

如果一个线程持有 object的钥匙,那么其他线程可以访问object对象没有上锁的方法,也就是非synchronized类型的方法。

四、Monitor和线程关系

首先看一下线程和 Monitor之间关系,以 及线程的状态转换图。通过图讲解一下整个过程。

上图分为三块:Entry Set(进入区) 、The Owner(拥有区)、Wait Set(等待区)。

Entry Set(进入区):表示线程通过synchronized要求获取对象的锁。如果对象未被锁住,则迚入拥有者;否则则在进入区等待。一旦对象锁被其他线程释放,立即参与竞争。

The Owner(拥有区):表示某一线程成功竞争到对象锁。

Wait Set(等待区):表示线程通过对象的wait方法,释放对象的锁,并在等待区等待被唤醒。

从图中可以看出,一个 Monitor在某个时刻,只能被一个线程拥有,该线程就是 “Active Thread”,而其它线程都是 “Waiting Thread”,分别在两个队列 “ Entry Set”和 “Wait Set”里面等候。

上面的内容讲解引自 :Java命令学习系列(二)——Jstack中关于Monitor的讲解。

参考文章

Java多线程编程核心技术

Java命令学习系列(二)——Jstack

自己因为比较喜欢技术,所以收集了一些Java高并发、分布式、JVM、spring、源码分析和kafka等架构技术资料

如果你也对技术感兴趣

资料获取方式:请加群BAT架构技术交流群:171662117

可以到群里来下载这些资料,欢迎大家进群讨论与学习。

上一篇 下一篇

猜你喜欢

热点阅读