新手向-同步关键字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 什么时候锁临界 ...
随机推荐
- Python学习---基础篇
###打开文件并打印: #!/usr/bin/python3 f = open('F://myproject/test.txt', encoding='utf-8',mode='r') content ...
- bootstrap栅格系统错位问题
在项目中div可以设置属性class=“col-size-x” //size取值为xs,sm,md,lg:x取值为1-12 可以让此div占据本行的 x/12 .col-xs- 超小屏幕 手机 (&l ...
- MT【161】韦恩图
(清华2017.4.29标准学术能力测试25) 若$N$的三个子集$A,B,C$满足$|A\cap B|=|B\cap C|=|C\cap A|=1$,且$A\cap B\cap C=\varnoth ...
- 洛谷3732:[HAOI2017]供给侧改革——题解
https://www.luogu.org/problemnew/show/P3732 Anihc国提高社会生产力水平.落实好以人民为中心的发展思想.决定进行供给侧结构性改革. 为了提高供给品质.你调 ...
- Alpha 冲刺 —— 十分之五
队名 火箭少男100 组长博客 林燊大哥 作业博客 Alpha 冲鸭鸭鸭鸭鸭! 成员冲刺阶段情况 林燊(组长) 过去两天完成了哪些任务 协调各成员之间的工作 协助测试的进行 测试项目运行的服务器环境 ...
- Android 65535 问题与 MultiDex分包
Android Multidex 遇到的问题 http://blog.csdn.net/wangbaochu/article/details/51178881 Android 使用android-su ...
- Android实现透明的颜色效果(zz)
android Button或者ImageButton背景透明状态设置 设置Button或ImageButton的背景为透明或者半透明 半透明< Button android:backgroun ...
- bzoj3203【sdoi2013】保护出题人
题目描述 输入格式 第一行两个空格隔开的正整数n和d,分别表示关数和相邻僵尸间的距离.接下来n行每行两个空格隔开的正整数,第i + 1行为Ai和 Xi,分别表示相比上一关在僵尸队列排头增加血量为Ai ...
- linux expect 的使用
expect 可以让一些需要交互的命令自动完成,如 ssh 连接的适合需要输入密码. 也就是说,某些重复的操作我们可以使用该命令完成,比如 ssh 连接到服务器,然后进到某个项目目录,进行 git 的 ...
- 四、Linux学习之文件处理命令
1.建立目录:mkdir 格式:mkdir –p [目录名] -p 递归创建目录 注意事项: 如果是创建单个目录直接mkdir [目录名就可以] 如果是创建一个目录下的目录也就是递归创建目录请 ...