Java同步块(synchronized block)使用详解
Java 同步块(synchronized block)用来标记方法或者代码块是同步的。Java同步块用来避免竞争。本文介绍以下内容:
- Java同步关键字(synchronzied)
- 实例方法同步
- 静态方法同步
- 实例方法中同步块
- 静态方法中同步块
- Java同步示例
Java 同步关键字(synchronized)
Java中的同步块用synchronized标记。同步块在Java中是同步在某个对象上。所有同步在一个对象上的同步块在同时只能被一个线程进入并执行操作。所有其他等待进入该同步块的线程将被阻塞,直到执行该同步块中的线程退出。
有四种不同的同步块:
- 实例方法
- 静态方法
- 实例方法中的同步块
- 静态方法中的同步块
上述同步块都同步在不同对象上。实际需要那种同步块视具体情况而定。
实例方法同步
下面是一个同步的实例方法:
public synchronized void add(int value){
this.count += value;
}
注意在方法声明中同步(synchronized )关键字。这告诉Java该方法是同步的。
Java实例方法同步是同步在拥有该方法的对象上。这样,每个实例其方法同步都同步在不同的对象上,即该方法所属的实例。只有一个线程能够在实例方法同步块中运行。如果有多个实例存在,那么一个线程一次可以在一个实例同步块中执行操作。一个实例一个线程。
静态方法同步
静态方法同步和实例方法同步方法一样,也使用synchronized 关键字。Java静态方法同步如下示例:
public static synchronized void add(int value){
count += value;
}
同样,这里synchronized 关键字告诉Java这个方法是同步的。
静态方法的同步是指同步在该方法所在的类对象上。因为在Java虚拟机中一个类只能对应一个类对象,所以同时只允许一个线程执行同一个类中的静态同步方法。
对于不同类中的静态同步方法,一个线程可以执行每个类中的静态同步方法而无需等待。不管类中的那个静态同步方法被调用,一个类只能由一个线程同时执行。
实例方法中的同步块
有时你不需要同步整个方法,而是同步方法中的一部分。Java可以对方法的一部分进行同步。
在非同步的Java方法中的同步块的例子如下所示:
public void add(int value){
synchronized(this){
this.count += value;
}
}
示例使用Java同步块构造器来标记一块代码是同步的。该代码在执行时和同步方法一样。
注意Java同步块构造器用括号将对象括起来。在上例中,使用了“this”,即为调用add方法的实例本身。在同步构造器中用括号括起来的对象叫做监视器对象。上述代码使用监视器对象同步,同步实例方法使用调用方法本身的实例作为监视器对象。
一次只有一个线程能够在同步于同一个监视器对象的Java方法内执行。
下面两个例子都同步他们所调用的实例对象上,因此他们在同步的执行效果上是等效的。
public class MyClass {
public synchronized void log1(String msg1, String msg2){
log.writeln(msg1);
log.writeln(msg2);
}
public void log2(String msg1, String msg2){
synchronized(this){
log.writeln(msg1);
log.writeln(msg2);
}
}
}
在上例中,每次只有一个线程能够在两个同步块中任意一个方法内执行。
如果第二个同步块不是同步在this实例对象上,那么两个方法可以被线程同时执行。
静态方法中的同步块
和上面类似,下面是两个静态方法同步的例子。这些方法同步在该方法所属的类对象上。
public class MyClass {
public static synchronized void log1(String msg1, String msg2){
log.writeln(msg1);
log.writeln(msg2);
}
public static void log2(String msg1, String msg2){
synchronized(MyClass.class){
log.writeln(msg1);
log.writeln(msg2);
}
}
}
这两个方法不允许同时被线程访问。
如果第二个同步块不是同步在MyClass.class这个对象上。那么这两个方法可以同时被线程访问。
Java同步实例
在下面例子中,启动了两个线程,都调用Counter类同一个实例的add方法。因为同步在该方法所属的实例上,所以同时只能有一个线程访问该方法。
public class Counter{
long count = 0;
public synchronized void add(long value){
this.count += value;
}
}
public class CounterThread extends Thread{
protected Counter counter = null;
public CounterThread(Counter counter){
this.counter = counter;
}
public void run() {
for(int i=0; i<10; i++){
counter.add(i);
}
}
}
public class Example {
public static void main(String[] args){
Counter counter = new Counter();
Thread threadA = new CounterThread(counter);
Thread threadB = new CounterThread(counter);
threadA.start();
threadB.start();
}
}
创建了两个线程。他们的构造器引用同一个Counter实例。Counter.add方法是同步在实例上,是因为add方法是实例方法并且被标记上synchronized关键字。因此每次只允许一个线程调用该方法。另外一个线程必须要等到第一个线程退出add()方法时,才能继续执行方法。
如果两个线程引用了两个不同的Counter实例,那么他们可以同时调用add()方法。这些方法调用了不同的对象,因此这些方法也就同步在不同的对象上。这些方法调用将不会被阻塞。如下面这个例子所示:
public class Example {
public static void main(String[] args){
Counter counterA = new Counter();
Counter counterB = new Counter();
Thread threadA = new CounterThread(counterA);
Thread threadB = new CounterThread(counterB);
threadA.start();
threadB.start();
}
}
注意这两个线程,threadA和threadB,不再引用同一个counter实例。CounterA和counterB的add方法同步在他们所属的对象上。调用counterA的add方法将不会阻塞调用counterB的add方法。
Java同步块(synchronized block)使用详解的更多相关文章
- Java精通并发-synchronized关键字原理详解
关于synchronized关键字原理其实在当时JVM的学习[https://www.cnblogs.com/webor2006/p/9595300.html]中已经剖析过了,这里从研究并发专题的角度 ...
- java多线程——同步块synchronized详解
Java 同步块(synchronized block)用来标记方法或者代码块是同步的.Java同步块用来避免竞争.本文介绍以下内容: Java同步关键字(synchronzied) 实例方法同步 静 ...
- 牛客网 Java 工程师能力评估 20 题 - 详解
牛客网 Java 工程师能力评估 20 题 - 详解 不知在看博客的你是否知道 牛客网,不知道就太落后了,分享给你 : 牛客网 此 20 题,绝对不只是 20 题! 免责声明:本博客为学习笔记,如有侵 ...
- Java性能分析之线程栈详解与性能分析
Java性能分析之线程栈详解 Java性能分析迈不过去的一个关键点是线程栈,新的性能班级也讲到了JVM这一块,所以本篇文章对线程栈进行基础知识普及以及如何对线程栈进行性能分析. 基本概念 线程堆栈也称 ...
- Java同步块
原文:http://ifeve.com/synchronized-blocks/ Java 同步块(synchronized block)用来标记方法或者代码块是同步的.Java同步块用来避免竞争.本 ...
- 12、Java并发性和多线程-Java同步块
以下内容转自http://ifeve.com/synchronized-blocks/: Java 同步块(synchronized block)用来标记方法或者代码块是同步的.Java同步块用来避免 ...
- java的集合框架最全详解
java的集合框架最全详解(图) 前言:数据结构对程序设计有着深远的影响,在面向过程的C语言中,数据库结构用struct来描述,而在面向对象的编程中,数据结构是用类来描述的,并且包含有对该数据结构操作 ...
- java线程池的使用与详解
java线程池的使用与详解 [转载]本文转载自两篇博文: 1.Java并发编程:线程池的使用:http://www.cnblogs.com/dolphin0520/p/3932921.html ...
- (7)Java数据结构--集合map,set,list详解
MAP,SET,LIST,等JAVA中集合解析(了解) - clam_clam的专栏 - CSDN博---有颜色, http://blog.csdn.net/clam_clam/article/det ...
随机推荐
- ASP.NET MVC Razor视图(2)
昨天介绍了一些Razor的基本语法,几天接着向下说: 补成一个,上次介绍了怎么输出原样的文本,用<text></text>标签,下面再介绍一种语法: @{@:我爱北京} 这个 ...
- 微软职位内部推荐-ATG Engineer II
微软近期Open的职位: ATG Engineer - GeneralistReady to work on some of the most advanced hardware on the pla ...
- 如何获得iphone设备的剩余空间
在手机终端开发的时候,我们需要关注手机剩余空间,因为手机不像电脑一样空间宽裕,当设备空间比较少得时候需要释放空间. 用法:先引入头文件 #include <sys/param.h> #in ...
- web中自定义鼠标样式
实现一个功能:鼠标移动到一个图片左边显示左箭头,移动到右边显示右箭头. 实现方法:一个img上面定位两个div,div的样式如下: .toleft { width: 200px; height: 30 ...
- 数据库备份,远程执行SHELL脚本
小小的东东,用于数据库的备份. 留存. #!/bin/sh keepDays= currentTime=`date "+%Y-%m-%d-%H-%M"` backPath=&quo ...
- ANDROID_MARS学习笔记_S02_003_AutoCompleteTextView
一. public class CountriesActivity extends Activity { protected void onCreate(Bundle icicle) { super. ...
- Android网络请求心路历程
HTTP请求&响应 既然说从入门级开始就说说Http请求包的结构.一次请求就是向目标服务器发送一串文本.什么样的文本?有下面结构的文本.HTTP请求包结构 例子: 1 2 3 4 5 6 7 ...
- BMS 项目过程中遇到的问题
环境搭建的问题 Git的ssh私人密钥问题, 路劲不正确的话使用ssh方式连接github进行远程push或clone会出现需要输入密码而怎么输入都不正确的情况,这个时候使用下面的办法: http方面 ...
- 如何关闭win7的ps/2兼容鼠标(触屏版)
买了一个新电脑联想ThinkPad E555 可是刚拿到是个win10 的系统,用习惯了win7,win0不太好用, 然后帮我刷成了win7,之后一切都好,性能也是让我很满意,但是却关不掉触控板,于是 ...
- Linux Kernel 整数溢出漏洞
漏洞名称: Linux Kernel 整数溢出漏洞 CNNVD编号: CNNVD-201311-062 发布时间: 2013-11-07 更新时间: 2013-11-07 危害等级: 漏洞类型: ...