原文链接 作者:Jakob Jenkov

Java 同步块(synchronized block)用来标记方法或者代码块是同步的。Java同步块用来避免竞争。本文介绍以下内容:

  • Java同步关键字(synchronzied)
  • 实例方法同步
  • 静态方法同步
  • 实例方法中同步块
  • 静态方法中同步块
  • Java同步示例

Java 同步关键字(synchronized

Java中的同步块用synchronized标记。同步块在Java中是同步在某个对象上。所有同步在一个对象上的同步块在同时只能被一个线程进入并执行操作。所有其他等待进入该同步块的线程将被阻塞,直到执行该同步块中的线程退出。

有四种不同的同步块:

  1. 实例方法
  2. 静态方法
  3. 实例方法中的同步块
  4. 静态方法中的同步块

上述同步块都同步在不同对象上。实际需要那种同步块视具体情况而定。

实例方法同步

下面是一个同步的实例方法:

1 public synchronized void add(int value){
2 this.count += value;
3  }

注意在方法声明中同步(synchronized )关键字。这告诉Java该方法是同步的。

Java实例方法同步是同步在拥有该方法的对象上。这样,每个实例其方法同步都同步在不同的对象上,即该方法所属的实例。只有一个线程能够在实例方法同步块中运行。如果有多个实例存在,那么一个线程一次可以在一个实例同步块中执行操作。一个实例一个线程。

静态方法同步

静态方法同步和实例方法同步方法一样,也使用synchronized 关键字。Java静态方法同步如下示例:

1 public static synchronized void add(int value){
2  count += value;
3  }

同样,这里synchronized 关键字告诉Java这个方法是同步的。

静态方法的同步是指同步在该方法所在的类对象上。因为在Java虚拟机中一个类只能对应一个类对象,所以同时只允许一个线程执行同一个类中的静态同步方法。

对于不同类中的静态同步方法,一个线程可以执行每个类中的静态同步方法而无需等待。不管类中的那个静态同步方法被调用,一个类只能由一个线程同时执行。

实例方法中的同步块

有时你不需要同步整个方法,而是同步方法中的一部分。Java可以对方法的一部分进行同步。

在非同步的Java方法中的同步块的例子如下所示:

1 public void add(int value){
2  
3     synchronized(this){
4        this.count += value;
5     }
6   }

示例使用Java同步块构造器来标记一块代码是同步的。该代码在执行时和同步方法一样。

注意Java同步块构造器用括号将对象括起来。在上例中,使用了“this”,即为调用add方法的实例本身。在同步构造器中用括号括起来的对象叫做监视器对象。上述代码使用监视器对象同步,同步实例方法使用调用方法本身的实例作为监视器对象。

一次只有一个线程能够在同步于同一个监视器对象的Java方法内执行。

下面两个例子都同步他们所调用的实例对象上,因此他们在同步的执行效果上是等效的。

01 public class MyClass {
02  
03    public synchronized void log1(String msg1, String msg2){
04       log.writeln(msg1);
05       log.writeln(msg2);
06    }
07  
08    public void log2(String msg1, String msg2){
09       synchronized(this){
10          log.writeln(msg1);
11          log.writeln(msg2);
12       }
13    }
14  }

在上例中,每次只有一个线程能够在两个同步块中任意一个方法内执行。

如果第二个同步块不是同步在this实例对象上,那么两个方法可以被线程同时执行。

静态方法中的同步块

和上面类似,下面是两个静态方法同步的例子。这些方法同步在该方法所属的类对象上。

01 public class MyClass {
02     public static synchronized void log1(String msg1, String msg2){
03        log.writeln(msg1);
04        log.writeln(msg2);
05     }
06  
07     public static void log2(String msg1, String msg2){
08        synchronized(MyClass.class){
09           log.writeln(msg1);
10           log.writeln(msg2);
11        }
12     }
13   }

这两个方法不允许同时被线程访问。

如果第二个同步块不是同步在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()方法。这些方法调用了不同的对象,因此这些方法也就同步在不同的对象上。这些方法调用将不会被阻塞。如下面这个例子所示:

01 public class Example {
02  
03    public static void main(String[] args){
04      Counter counterA = new Counter();
05      Counter counterB = new Counter();
06      Thread  threadA = new CounterThread(counterA);
07      Thread  threadB = new CounterThread(counterB);
08  
09      threadA.start();
10      threadB.start();
11    }
12  }

注意这两个线程,threadA和threadB,不再引用同一个counter实例。CounterA和counterB的add方法同步在他们所属的对象上。调用counterA的add方法将不会阻塞调用counterB的add方法。

(全文完)

转自:http://ifeve.com/synchronized-blocks/

转:Java同步synchronized使用的更多相关文章

  1. java同步synchronized

    java同步synchronized volatile仅仅用来保证该变量对所有线程的可见性,但不保证原子性. 看下面的这段代码: /** * * @author InJavaWeTrust * */ ...

  2. Java同步synchronized与死锁

    多个线程要操作同一资源时就有可能出现资源的同步问题. 同步就是指多个操作在同一个时间段内只能有一个线程进行,其他线程要等待此线程完成之后才可以继续执行. 解决资源共享的同步操作,可以使用同步代码块和同 ...

  3. java 同步 synchronized

    http://www.cnblogs.com/Qian123/p/5691705.html http://www.cnblogs.com/GnagWang/archive/2011/02/27/196 ...

  4. Java多线程同步 synchronized 关键字的使用

    代表这个方法加锁,相当于不管哪一个线程A每次运行到这个方法时,都要检查有没有其它正在用这个方法的线程B(或者C D等),有的话要等正在使用这个方法的线程B(或者C D)运行完这个方法后再运行此线程A, ...

  5. Java的synchronized关键字:同步机制总结

    JAVA中synchronized关键字能够作为函数的修饰符,也可作为函数内的语句,也就是平时说的同步方法和同步语句块.搞清楚synchronized锁定的是哪个对象,就能帮助我们设计更安全的多线程程 ...

  6. Java同步块(synchronized block)使用详解

    Java 同步块(synchronized block)用来标记方法或者代码块是同步的.Java同步块用来避免竞争.本文介绍以下内容: Java同步关键字(synchronzied) 实例方法同步 静 ...

  7. 015-线程同步-synchronized几种加锁方式、Java对象头和Monitor、Mutex Lock、JDK1.6对synchronized锁的优化实现

    一.synchronized概述基本使用 为确保共享变量不会出现并发问题,通常会对修改共享变量的代码块用synchronized加锁,确保同一时刻只有一个线程在修改共享变量,从而避免并发问题. syn ...

  8. “全栈2019”Java多线程第十六章:同步synchronized关键字详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

  9. Java同步机制总结--synchronized

    不久前用到了同步,现在回过头来对JAVA中的同步做个总结,以对前段时间工作的总结和自我技术的条理话.JAVA中synchronized关键字能够 作为函数的修饰符,也可作为函数内的语句,也就是平时说的 ...

随机推荐

  1. VS2012 无法启动IIS Express Web服务器的解决方案

    本文转载:http://blog.csdn.net/hongleidy5000/article/details/22732621 打开VS2012解决方案资源管理器 -> 点选 Web 项目选择 ...

  2. Configuration所有配置简介

    // 内存缓存的设置选项 (最大图片宽度,最大图片高度) 默认当前屏幕分辨率                // .memoryCacheExtraOptions(480, 800) // 硬盘缓存的 ...

  3. 《HTML5 从入门到精通--7.6.3 单元格垂直跨度——rowspan》

    单元格除了能够在水平方向上跨列,还能够垂直方向上跨行.跨行设置须要使用rowspan參数. 语法 <td rowspan="单元格跨行数"> 语法解释 与水平跨度相相应 ...

  4. OpenStack Cinder源代码流程简析

    版权声明:本博客欢迎转载,转载时请以超链接形式标明文章原始出处!谢谢! 博客地址:http://blog.csdn.net/i_chips 一.概况 OpenStack的各个模块都有对应的client ...

  5. python-列表、字典、元组的员工信息处理接口(第二篇(五):基于列表、字典和元组的员工信息处理接口)

    Python之旅]第二篇(五):基于列表.字典和元组的员工信息处理接口 python 列表 字典 元组 员工信息处理接口 摘要: 1.基本需求     编写一个查询员工信息表的程序,实现如下功能: ( ...

  6. IntentFilter

    当Intent在组件间传递时,组件如果想告知Android系统自己能够响应和处理哪些Intent,那么就需要用到IntentFilter对象. 顾名思义,IntentFilter对象负责过滤掉组件无法 ...

  7. VB几种函数参数传递方法,Variant,数组,Optional,ParamArray

    VB几种函数参数传递方法,Variant,数组,Optional,ParamArray 一) 过程的参数被缺省为具有 Variant 数据类型. 1)ByRef按 地址传递参数在 VB 中是缺省的 按 ...

  8. Django runserver show client ip

    get path of basehttp.py $ python >>> import site >>> site.getsitepackages() ['/usr ...

  9. 学习CSS一些事(下)

    2.浮动(float) 浮动(float)特点:1.元素会左移.右移,直到触碰到容器为止.    2.设置浮动元素,仍旧处于标准文档流. 3.当元素没有设置宽度值,而设置了浮动属性,元素的宽度随着内容 ...

  10. 触发TreeView的TreeNodeCheckChanged事件

    这个事件不会主动postback,需要手动写javascript触发.对网上找到的方法做了些改进,增加UpdatePanel,以免页面不停的刷.这里就不考虑性能神马的了,因为既然项目已经允许选择使用T ...