原文: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. Eclipse 复制按钮卡死

    复制按钮和按住CTRL链着超链接 有冲突,Eclipse不知道是复制还是链到元素,所以卡死 Eclipse/MyEclipse中使用复制粘贴功能卡的解决办法 最近在MyEclipse中编辑代码时,使用 ...

  2. C# 数组,ArrayList与List对象的区别

    在C#中,当我们想要存储一组对象的时候,就会想到用数组,ArrayList,List这三个对象了.那么这三者到底有什么样的区别呢? 我们先来了解一下数组,因为数组在C#中是最早出现的. 数组 数组有很 ...

  3. Avoiding PostgreSQL database corruption

    TL;DR: Don't ever set fsync=off, don't kill -9 the postmaster then deletepostmaster.pid, don't run P ...

  4. sed的实际用法举例

    sed:Stream Editor文本流编辑,sed是一个“非交互式的”面向字符流的编辑器.能同时处理多个文件多行的内容,可以不对原文件改动,把整个文件输入到屏幕,可以把只匹配到模式的内容输入到屏幕上 ...

  5. PHP实现动态规划背包问题

    有一堆货物,有各种大小和价值不等的多个物品,而你只有固定大小的背包,拿走哪些能保证你的背包带走的价值最多 动态规划就是可以记录前一次递归过程中计算出的最大值,在之后的递归期间使用,以免重复计算. &l ...

  6. C#中锁定Word内容,样把人家的锁定内容破解了

    原文地址:http://www.cnblogs.com/name-lh/archive/2007/04/29/732620.html     教您怎样在C#中锁定Word内容,还教您怎样把人家的锁定内 ...

  7. 安装max plugin wizard

    参考:http://liweizhaolili.blog.163.com/blog/static/162307442013117731953/

  8. vs2010编译lua-5.3.2

    lua-5.3.2.tar.gz 解开在 D:\lua 1. 启动VS命令行 2. c:\program files\microsoft visual studio 10.0\vc\bin>cd ...

  9. jQuery选择器大全(48个代码片段+21幅图演示)

    选择器是jQuery最基础的东西,本文中列举的选择器基本上囊括了所有的jQuery选择器,也许各位通过这篇文章能够加深对jQuery选择器 的理解,它们本身用法就非常简单,我更希望的是它能够提升个人编 ...

  10. HTTP API 设计指南(中文版) restfull

    http://www.css88.com/archives/5121 目录 基础 总是使用TLS 在Accepts头中带上版本号 通过Etags支持缓存 用Request-Ids追踪请求 用Range ...