Java中使用同步关键字synchronized需要注意的问题
在Java中,synchronized关键字是用来控制线程同步的,就是在多线程的环境下,控制synchronized代码段不被多个线程同时执行。synchronized既可以加在一段代码上,也可以加在方法上。
关键是,不要认为给方法或者代码段加上synchronized就万事大吉,看下面一段代码:
class Sync { public synchronized void test() {
System.out.println("test开始..");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("test结束..");
}
} class MyThread extends Thread { public void run() {
Sync sync = new Sync();
sync.test();
}
} public class Main { public static void main(String[] args) {
for (int i = 0; i < 3; i++) {
Thread thread = new MyThread();
thread.start();
}
}
}
运行结果:
test开始..
test开始..
test开始..
test结束..
test结束..
test结束..
可以看出来,上面的程序起了三个线程,同时运行Sync类中的test()方法,虽然test()方法加上了synchronized,但是还是同时运行起来,貌似synchronized没起作用。
将test()方法上的synchronized去掉,在方法内部加上synchronized(this):
public void test() {
synchronized(this){
System.out.println("test开始..");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("test结束..");
}
}
运行结果:
test开始..
test开始..
test开始..
test结束..
test结束..
test结束..
一切还是这么平静,没有看到synchronized起到作用。
实际上,synchronized(this)以及非static的synchronized方法(至于static synchronized方法请往下看),只能防止多个线程同时执行同一个对象的同步代码段。
回到本文的题目上:synchronized锁住的是代码还是对象。答案是:synchronized锁住的是括号里的对象,而不是代码。对于非static的synchronized方法,锁的就是对象本身也就是this。
当synchronized锁住一个对象后,别的线程如果也想拿到这个对象的锁,就必须等待这个线程执行完成释放锁,才能再次给对象加锁,这样才达到线程同步的目的。即使两个不同的代码段,都要锁同一个对象,那么这两个代码段也不能在多线程环境下同时运行。
所以我们在用synchronized关键字的时候,能缩小代码段的范围就尽量缩小,能在代码段上加同步就不要再整个方法上加同步。这叫减小锁的粒度,使代码更大程度的并发。原因是基于以上的思想,锁的代码段太长了,别的线程是不是要等很久,等的花儿都谢了。当然这段是题外话,与本文核心思想并无太大关联。
再看上面的代码,每个线程中都new了一个Sync类的对象,也就是产生了三个Sync对象,由于不是同一个对象,所以可以多线程同时运行synchronized方法或代码段。
为了验证上述的观点,修改一下代码,让三个线程使用同一个Sync的对象。
class MyThread extends Thread { private Sync sync; public MyThread(Sync sync) {
this.sync = sync;
} public void run() {
sync.test();
}
} public class Main { public static void main(String[] args) {
Sync sync = new Sync();
for (int i = 0; i < 3; i++) {
Thread thread = new MyThread(sync);
thread.start();
}
}
}
运行结果:
test开始..
test结束..
test开始..
test结束..
test开始..
test结束..
可以看到,此时的synchronized就起了作用。
那么,如果真的想锁住这段代码,要怎么做?也就是,如果还是最开始的那段代码,每个线程new一个Sync对象,怎么才能让test方法不会被多线程执行。
解决也很简单,只要锁住同一个对象不就行了。例如,synchronized后的括号中锁同一个固定对象,这样就行了。这样是没问题,但是,比较多的做法是让synchronized锁这个类对应的Class对象。
class Sync { public void test() {
synchronized (Sync.class) {
System.out.println("test开始..");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("test结束..");
}
}
} class MyThread extends Thread { public void run() {
Sync sync = new Sync();
sync.test();
}
} public class Main { public static void main(String[] args) {
for (int i = 0; i < 3; i++) {
Thread thread = new MyThread();
thread.start();
}
}
}
运行结果:
test开始..
test结束..
test开始..
test结束..
test开始..
test结束..
上面代码用synchronized(Sync.class)实现了全局锁的效果。
最后说说static synchronized方法,static方法可以直接类名加方法名调用,方法中无法使用this,所以它锁的不是this,而是类的Class对象,所以,static synchronized方法也相当于全局锁,相当于锁住了代码段。
Java中使用同步关键字synchronized需要注意的问题的更多相关文章
- java中实现同步的两种方式:syschronized和lock的区别和联系
Lock是java.util.concurrent.locks包下的接口,Lock 实现提供了比使用synchronized 方法和语句可获得的更广泛的锁定操作,它能以更优雅的方式处理线程同步问题,我 ...
- java多线程学习-同步(synchronized)
(示例都是网上视频的) 假如两个线程同时调用一个方法输出字符串 public class SynchronizedTest extends Thread { public static void ma ...
- 同步关键字synchronized
同步关键字synchronized 同步关键字synchronized使用简洁,代码可维护性好.在JDK6中,性能也比早期的JDK有很大的改进.如果可以满足程序要求,应该首先考虑这种同步方式. 关键字 ...
- Java中的Lock与synchronized
并发编程学习笔记之Lock与synchronized 一.什么是可重入锁 Lcok在Java中是一个接口,一般在面试问题中问到的可能是ReentrantLock与synchronized的区别.Ree ...
- Java中线程同步的理解 - 其实应该叫做Java线程排队
Java中线程同步的理解 我们可以在计算机上运行各种计算机软件程序.每一个运行的程序可能包括多个独立运行的线程(Thread). 线程(Thread)是一份独立运行的程序,有自己专用的运行栈.线程有可 ...
- 深入理解Java中的volatile关键字
在再有人问你Java内存模型是什么,就把这篇文章发给他中我们曾经介绍过,Java语言为了解决并发编程中存在的原子性.可见性和有序性问题,提供了一系列和并发处理相关的关键字,比如synchronized ...
- java中线程同步的理解(非常通俗易懂)
转载至:https://blog.csdn.net/u012179540/article/details/40685207 Java中线程同步的理解 我们可以在计算机上运行各种计算机软件程序.每一个运 ...
- 深入理解Java中的final关键字
Java中的final关键字非常重要,它可以应用于类.方法以及变量.这篇文章中我将带你看看什么是final关键字?将变量,方法和类声明为final代表了什么?使用final的好处是什么?最后也有一些使 ...
- (转)深入理解Java中的final关键字
转自:http://www.importnew.com/7553.html Java中的final关键字非常重要,它可以应用于类.方法以及变量.这篇文章中我将带你看看什么是final关键字?将变量,方 ...
随机推荐
- Mysql 学习1
Mysql学习 一.数据库 1 数据库概念(了解) 1.1 什么是数据库 数据库就是用来存储和管理数据的仓库! 数据库存储数据的优先: 可存储大量数据: 方便检索: 保持数据的一致性.完整 ...
- Computer Vision: Algorithms and ApplicationsのImage processing
实在是太喜欢Richard Szeliski的这本书了.每一章节(after chapter3)都详述了该研究方向比較新的成果.还有很多很多的reference,假设你感兴趣.全然能够看那些參考论文 ...
- Intel Quick Sync Video Encoder
本篇记录Intel E3 1275处理器集成显卡的硬编码预研过程. 步骤如下: (1)环境搭建 (2)demo编译,测试 (3)研究demo源码,Media SDK API使用 (4)编写so动态库封 ...
- 关于VMAX中存储资源池(SRP)
Storage Resource Pool中的相关元素 SRP由一个或多个数据池组成,这些数据池包含了预配置的数据(或TDAT)设备,可为创建和呈现给主机与应用程序的精简设备(TDEVS) 提供存储. ...
- linux shell 中数组使用方法介绍
linux shell在编程方面比windows 批处理强大太多,不管是在循环.运算.已经数据类型方面都是不能比較的. 以下是个人在使用时候,对它在数组方面一些操作进行的总结. 1.数组定义 [che ...
- Mac下XAMPP环境中安装MySQLdb
环境: Mac OS X. Mac下安装MySQLdb模块着实多了些步骤. 用easy_install或者pip安装时有两大问题,"mysql_config not found"和 ...
- action extension添加图标
最近在做ios的action extension,这里记录一下添加图标的方法. 在Action Extension的target里面的Build Settings,里面的Asset Catalog C ...
- STM32 JTDO JREST复用为普通IO
一.开启AFIO的时钟(必须保证先打开AFIO,否则无效) RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); 二.禁用JTAG,使能SWD GP ...
- 【Flask模板】宏的概念和基本使用
# 宏:模板中的宏跟python中的函数类似,可以传递参数,但是不能有返回值,可以将一些经常用到的代码片段放到宏中,然后把一些不固定的值抽取出来当成一个变量.使用宏的时候,参数可以为默认值.相关示例代 ...
- Unity Json解析IPA
今天看到一个unity 自带的解析json的IPA,感觉比litjson好用很多,废话不多,上代码 using System.Collections; using System.Collections ...