新手向-同步关键字synchronized对this、class、object、方法的区别
在看源代码时遇到多线程需要同步的时候,总是会看见几种写法,修饰方法、修饰静态方法、
synchronized(Xxx.class)、synchronized(this)、synchronized(obj),之前一直没深究几种方式的区别,现在想来真是惊出一身冷汗,居然这个问题都没有仔细想清楚。
synchronized的语义
每个对象都有一个监视器monitor,被synchronized修饰,语义就是获取这个对象的monitor,反编译后可以看到monitorenter和monitorexit。synchronized关键字有三种应用方式(其实按标题来讲应该是5种,但是其中有两种都是与另外两种等价的):
- 修饰实例方法
- 修饰静态方法
- 修饰代码块(指定对象)
实验
先上代码做实验验证一下
public class SyncThread {
private final Object lock = new Object();
public void foo() throws Exception {
synchronized (SyncThread.class) {
for (int i = 0; i < 5; i++) {
System.out.println(">>>foo: " + i);
Thread.sleep(1000);
}
}
}
public void bar() throws Exception {
synchronized (this) {
for (int i = 0; i < 5; i++) {
System.out.println("<<<bar: " + i);
Thread.sleep(1000);
}
}
}
public void cpp() throws Exception {
synchronized (lock) {
for (int i = 0; i < 5; i++) {
System.out.println("===cpp: " + i);
Thread.sleep(1000);
}
}
}
public void der() throws Exception {
for (int i = 0; i < 5; i++) {
System.out.println("!!!der: " + i);
Thread.sleep(1000);
}
}
}
可以看到有四种不同的synchronized修饰,以及一个没有同步的方法,再运行一下看看结果
public class ThreadApp {
public static void main(String[] args) {
final SyncThread syncThread = new SyncThread();
new Thread(() -> {
try {
syncThread.foo();
} catch (Exception e) {
e.printStackTrace();
}
}).start();
new Thread(() -> {
try {
syncThread.bar();
} catch (Exception e) {
e.printStackTrace();
}
}).start();
new Thread(() -> {
try {
syncThread.cpp();
} catch (Exception e) {
e.printStackTrace();
}
}).start();
new Thread(() -> {
try {
syncThread.der();
} catch (Exception e) {
e.printStackTrace();
}
}).start();
}
}
可以看到结果
>>>foo: 0
<<<bar: 0
===cpp: 0
!!!der: 0
>>>foo: 1
===cpp: 1
<<<bar: 1
!!!der: 1
>>>foo: 2
!!!der: 2
<<<bar: 2
===cpp: 2
>>>foo: 3
<<<bar: 3
===cpp: 3
!!!der: 3
>>>foo: 4
!!!der: 4
<<<bar: 4
===cpp: 4
分析
从以上结果来看各线程并没有发生竞争,互不影响,其实明白了synchronized语义也很好理解以上结果,几个synchronized获取的monitor都不是一个,当然相互不影响。
但是值得注意的几点:
synchronized(Xxx.class)获取的是类的monitor,所以与public synchronized static void some()修饰静态方法是等价的synchronized(this)获取的是当前实例的monitor,所以与public synchronized void some()修饰实例方法是等价的
以上两点可以通过修改上述代码中方法可以很容易验证,我们修改最后一个方法
public synchronized static void der() throws Exception {
for (int i = 0; i < 5; i++) {
System.out.println("!!!der: " + i);
Thread.sleep(1000);
}
}
运行得到结果
!!!der: 0
!!!der: 1
!!!der: 2
!!!der: 3
!!!der: 4
>>>foo: 0
>>>foo: 1
>>>foo: 2
>>>foo: 3
>>>foo: 4
可以看到,确实synchronized(Xxx.class)与synchronized修饰静态方法是等价的。再修改为synchronized修饰实例方法
public synchronized void der() throws Exception {
for (int i = 0; i < 5; i++) {
System.out.println("!!!der: " + i);
Thread.sleep(1000);
}
}
运行查看结果
<<<bar: 0
<<<bar: 1
<<<bar: 2
<<<bar: 3
<<<bar: 4
!!!der: 0
!!!der: 1
!!!der: 2
!!!der: 3
!!!der: 4
可以看到,确实synchronized(this)与synchronized修饰实例方法是等价的。
总之,个人认为要理解几种不一样的地方,关键是理解清楚是获取的谁的monitor,只要是同一个monitor,当然就会发生同步!
新手向-同步关键字synchronized对this、class、object、方法的区别的更多相关文章
- 同步关键字synchronized
同步关键字synchronized 同步关键字synchronized使用简洁,代码可维护性好.在JDK6中,性能也比早期的JDK有很大的改进.如果可以满足程序要求,应该首先考虑这种同步方式. 关键字 ...
- synchronized和volatile的使用方法以及区别
先看看下面的例子: public class ThreadTest { public static void main(String[] args) { final Counter counter = ...
- Java中使用同步关键字synchronized需要注意的问题
在Java中,synchronized关键字是用来控制线程同步的,就是在多线程的环境下,控制synchronized代码段不被多个线程同时执行.synchronized既可以加在一段代码上,也可以加在 ...
- java多线程学习-同步(synchronized)
(示例都是网上视频的) 假如两个线程同时调用一个方法输出字符串 public class SynchronizedTest extends Thread { public static void ma ...
- java中实现同步的两种方式:syschronized和lock的区别和联系
Lock是java.util.concurrent.locks包下的接口,Lock 实现提供了比使用synchronized 方法和语句可获得的更广泛的锁定操作,它能以更优雅的方式处理线程同步问题,我 ...
- 多线程,线程同步,synchronized关键字的用法
一.什么是多线程 Java多线程实现方式主要有四种:继承Thread类.实现Runnable接口.实现Callable接口通过FutureTask包装器来创建Thread线程.使用ExecutorSe ...
- Java:多线程,线程同步,synchronized关键字的用法(同步代码块、非静态同步方法、静态同步方法)
关于线程的同步,可以使用synchronized关键字,或者是使用JDK 5中提供的java.util.concurrent.lock包中的Lock对象.本文探讨synchronized关键字. sy ...
- 5.同步关键字(synchronized)
同步关键字(synchronized): 多线程给我们提供方便的时候,也给整个编程增加了难度,尤其是对临界资源的控制,尤为重要. 一个在操作系统课上,老掉牙的事例,就把这种情况解释的明明白白. 一对夫 ...
- 多线程总结-同步之synchronized关键字
目录 1.为什么要使用synchronized? 2.synchronized锁什么,加锁的目的是什么? 3.代码示例 3.1锁this和临界资源对象 3.2锁class类对象 3.3 什么时候锁临界 ...
随机推荐
- 【uoj#143】[UER #5]万圣节的数列 构造
题目描述 给出一个的数列,将其重新排列,使得其等差子序列的数目最小.输出一种可能的排列后的数列. 题解 构造 那天和 EdwardFrog 讨论 bzoj2124 的构造时突然有的灵感,最后发现就是这 ...
- 对HashMap的理解(三):ConcurrentHashMap
HashMap不是线程安全的.在并发插入元素的时候,有可能出现环链表,让下一次读操作出现死循环.避免HashMap的线程安全问题有很多方法,比如改用HashTable或Collections.sync ...
- Vue设置不同的环境发布程序
原文地址: http://www.cnblogs.com/JimmyBright/p/7307486.html 通常应用程序上线都会经过开发环境.测试环境.生产环境三个阶段,三个环境通常会对应有三个不 ...
- ThinkPHP 5.x远程命令执行漏洞分析与复现
0x00 前言 ThinkPHP官方2018年12月9日发布重要的安全更新,修复了一个严重的远程代码执行漏洞.该更新主要涉及一个安全更新,由于框架对控制器名没有进行足够的检测会导致在没有开启强制路由的 ...
- 响应式开发(三)-----Bootstrap框架的安装使用
下载 Bootstrap 可以从http://getbootstrap.com/上下载 Bootstrap 的最新版本. Download Bootstrap:下载 Bootstrap.点击该按钮,您 ...
- [THUSC 2016] 补退选 (Trie树)
link $solution:$ $Trie$树很显然吧,那么如何去处理每次询问.对于$Trie$树的每个节点放一个$vector$表示其若有$v$个人的最小时间. #include<iostr ...
- noip2017考前整理(未完)
快考试了,把我以前写过的题回顾一下.Noip2007 树网的核:floyd,推出性质,暴力.Noip2008 笨小猴:模拟Noip2008 火柴棒等式:枚举Noip2008 传纸条:棋盘dpNoip2 ...
- bootstrap.yml与application.yml的区别
说明:其实yml和properties文件是一样的原理,主要是说明application和bootstrap的加载顺序.且一个项目上要么yml或者properties,二选一的存在. Bootstra ...
- Python【接口开发】
import flaskimport json #步骤一:# __name__,代表当前这个python文件server = flask.Flask(__name__) #把咱们当前这个python文 ...
- P2207 Photo
P2207 Photo 题目描述 Framer Jhon 打算给他的N头奶牛照相,( 2 <= N <= 1 000 000 000) . 他们排成一条线,并且依次取1~N作为编号. 每一 ...