原文:http://ifeve.com/synchronized-blocks/

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方法。因为同步在该方法所属的实例上,所以同时只能有一个线程访问该方法。

01 public class Counter{
02      long count = 0;
03  
04      public synchronized void add(long value){
05        this.count += value;
06      }
07   }
08   public class CounterThread extends Thread{
09  
10      protected Counter counter = null;
11  
12      public CounterThread(Counter counter){
13         this.counter = counter;
14      }
15  
16      public void run() {
17     for(int i=0; i<10; i++){
18            counter.add(i);
19         }
20      }
21   }
22   public class Example {
23  
24     public static void main(String[] args){
25       Counter counter = new Counter();
26       Thread  threadA = new CounterThread(counter);
27       Thread  threadB = new CounterThread(counter);
28  
29       threadA.start();
30       threadB.start();
31     }
32   }

创建了两个线程。他们的构造器引用同一个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方法。

Java同步块的更多相关文章

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

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

  2. 12、Java并发性和多线程-Java同步块

    以下内容转自http://ifeve.com/synchronized-blocks/: Java 同步块(synchronized block)用来标记方法或者代码块是同步的.Java同步块用来避免 ...

  3. java多线程-同步块

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

  4. java多线程——同步块synchronized详解

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

  5. Java并发编程(六)-- 同步块

    上一节已经讲到,使用Synchronzied代码块可以解决共享对象的竞争问题,其实还有其他的方法也可以避免资源竞争问题,我统称他们为Java同步块.Java 同步块(synchronized bloc ...

  6. synchronized同步块和volatile同步变量

    Java语言包含两种内在的同步机制:同步块(或方法)和 volatile 变量.这两种机制的提出都是为了实现代码线程的安全性.其中 Volatile 变量的同步性较差(但有时它更简单并且开销更低),而 ...

  7. 转:Java同步synchronized使用

    原文链接 作者:Jakob Jenkov Java 同步块(synchronized block)用来标记方法或者代码块是同步的.Java同步块用来避免竞争.本文介绍以下内容: Java同步关键字(s ...

  8. Java 同步代码块 - Synchronized Blocks

    java锁实现原理: http://blog.csdn.net/endlu/article/details/51249156 The synchronized keyword can be used ...

  9. [转]关于java中的 sychronized 同步方法 与 同步块的理解

    首先,需要说明一点,也是最重要的一点,无论是同步方法 还是 同步块 都是只针对同一个对象的多线程而言的,只有同一个对象产生的多线程,才会考虑到 同步方法 或者是 同步块,如果定义多个实例的同步,可以考 ...

随机推荐

  1. Attention and Augmented Recurrent Neural Networks

    Attention and Augmented Recurrent Neural Networks CHRIS OLAHGoogle Brain SHAN CARTERGoogle Brain Sep ...

  2. about java techelogly

    https://docs.oracle.com/javase/tutorial/getStarted/intro/definition.html Differences between Java EE ...

  3. linux服务之nfs

    开发语言:rpc编程环境 服务器端:在linux平台下部署 客户端:一般是cli界面下的mount命令 相关包:rpcbind,nfs-utils 背景 http://nfs.sourceforge. ...

  4. 《腾讯敏捷框架TAPD》研究

    1         框架结构 1.1         产品 TAPD采用FDD模式开发,FDD即特征驱动开发. FDD的核心是面向产品的功能点,但这个功能点是从客户角度出发的,并不是从系统角度出来的. ...

  5. mongoDB 下载/安装/客户端笔记

    1.下载: https://fastdl.mongodb.org/win32/mongodb-win32-x86_64-3.0.3.zip 2.安装 1.解压mongodb-win32-x86 64- ...

  6. 基于LBS的地理位置附近的搜索以及由近及远的排序

    Nosql学习之Redis资料(一) http://redis.io/download 目前基于LBS地理位置的搜索已经应用非常广了,的确是个很方便的东西. 我们做程序的就是要考虑如何通过这些功能,来 ...

  7. Nginx 性能优化

    1.安全优化:隐藏Nginx版本号,server_tokens off; 2.安全优化:更改掉默认的用户  user nginx; 3.性能优化:  根据硬件配置,调整nginx worker 进程数 ...

  8. DataRow[] 转为数组

    DataRow[] rows = dt.Select("1=1"); ].ToString()).ToArray();

  9. EventBus学习

    Git位置https://github.com/greenrobot/EventBus 使用起来很方便:1. Implement any number of event handling method ...

  10. Nova分析(1)——整体架构

    Conceptual Diagram Logical diagram Nova is the most complicated and distributed component of OpenSta ...