Java 同步块(synchronized block)用来标记方法或者代码块是同步的。Java同步块用来避免竞争。本文介绍以下内容:
- Java同步关键字(synchronzied)
- 实例方法同步
- 静态方法同步
- 实例方法中同步块
- 静态方法中同步块
- Java同步示例
Java 同步关键字(synchronized)
Java中的同步块用synchronized标记。同步块在Java中是同步在某个对象上。所有同步在一个对象上的同步块在同时只能被一个线程进入并执行操作。所有其他等待进入该同步块的线程将被阻塞,直到执行该同步块中的线程退出。
有四种不同的同步块:
- 实例方法
- 静态方法
- 实例方法中的同步块
- 静态方法中的同步块
上述同步块都同步在不同对象上。实际需要那种同步块视具体情况而定。
实例方法同步
下面是一个同步的实例方法:
1 |
public synchronized void add(int value){ |
注意在方法声明中同步(synchronized )关键字。这告诉Java该方法是同步的。
Java实例方法同步是同步在拥有该方法的对象上。这样,每个实例其方法同步都同步在不同的对象上,即该方法所属的实例。只有一个线程能够在实例方法同步块中运行。如果有多个实例存在,那么一个线程一次可以在一个实例同步块中执行操作。一个实例一个线程。
静态方法同步
静态方法同步和实例方法同步方法一样,也使用synchronized 关键字。Java静态方法同步如下示例:
1 |
public static synchronized void add(int value){ |
同样,这里synchronized 关键字告诉Java这个方法是同步的。
静态方法的同步是指同步在该方法所在的类对象上。因为在Java虚拟机中一个类只能对应一个类对象,所以同时只允许一个线程执行同一个类中的静态同步方法。
对于不同类中的静态同步方法,一个线程可以执行每个类中的静态同步方法而无需等待。不管类中的那个静态同步方法被调用,一个类只能由一个线程同时执行。
实例方法中的同步块
有时你不需要同步整个方法,而是同步方法中的一部分。Java可以对方法的一部分进行同步。
在非同步的Java方法中的同步块的例子如下所示:
1 |
public void add(int value){ |
示例使用Java同步块构造器来标记一块代码是同步的。该代码在执行时和同步方法一样。
注意Java同步块构造器用括号将对象括起来。在上例中,使用了“this”,即为调用add方法的实例本身。在同步构造器中用括号括起来的对象叫做监视器对象。上述代码使用监视器对象同步,同步实例方法使用调用方法本身的实例作为监视器对象。
一次只有一个线程能够在同步于同一个监视器对象的Java方法内执行。
下面两个例子都同步他们所调用的实例对象上,因此他们在同步的执行效果上是等效的。
01 |
public class MyClass { |
03 |
public synchronized void log1(String msg1, String msg2){ |
08 |
public void log2(String msg1, String msg2){ |
在上例中,每次只有一个线程能够在两个同步块中任意一个方法内执行。
如果第二个同步块不是同步在this实例对象上,那么两个方法可以被线程同时执行。
静态方法中的同步块
和上面类似,下面是两个静态方法同步的例子。这些方法同步在该方法所属的类对象上。
01 |
public class MyClass { |
02 |
public static synchronized void log1(String msg1, String msg2){ |
07 |
public static void log2(String msg1, String msg2){ |
08 |
synchronized(MyClass.class){ |
这两个方法不允许同时被线程访问。
如果第二个同步块不是同步在MyClass.class这个对象上。那么这两个方法可以同时被线程访问。
Java同步实例
在下面例子中,启动了两个线程,都调用Counter类同一个实例的add方法。因为同步在该方法所属的实例上,所以同时只能有一个线程访问该方法。
04 |
public synchronized void add(long value){ |
08 |
public class CounterThread extends Thread{ |
10 |
protected Counter counter = null; |
12 |
public CounterThread(Counter counter){ |
13 |
this.counter = counter; |
17 |
for(int i=0; i<10; i++){ |
22 |
public class Example { |
24 |
public static void main(String[] args){ |
25 |
Counter counter = new Counter(); |
26 |
Thread threadA = new CounterThread(counter); |
27 |
Thread threadB = new CounterThread(counter); |
创建了两个线程。他们的构造器引用同一个Counter实例。Counter.add方法是同步在实例上,是因为add方法是实例方法并且被标记上synchronized关键字。因此每次只允许一个线程调用该方法。另外一个线程必须要等到第一个线程退出add()方法时,才能继续执行方法。
如果两个线程引用了两个不同的Counter实例,那么他们可以同时调用add()方法。这些方法调用了不同的对象,因此这些方法也就同步在不同的对象上。这些方法调用将不会被阻塞。如下面这个例子所示:
01 |
public class Example { |
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); |
注意这两个线程,threadA和threadB,不再引用同一个counter实例。CounterA和counterB的add方法同步在他们所属的对象上。调用counterA的add方法将不会阻塞调用counterB的add方法。
转载自并发编程网 – ifeve.com
- Java 多线程同步和异步详解
java线程 同步与异步 线程池 1)多线程并发时,多个线程同时请求同一个资源,必然导致此资源的数据不安全,A线程修改了B线 程的处理的数据,而B线程又修改了A线程处理的数理.显然这是由于全局资源造成 ...
- java线程同步: synchronized详解(转)
Java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码. 一.当两个并发线程访问同一个对象object中的这个synchronized(this ...
- Java多线程之synchronized详解
目录 synchronized简介 同步的原理 对象头与锁的实现 锁的优化与升级 Monitor Record 锁的对比 synchronized简介 synchronized关键字,一般称之为&qu ...
- java多线程-同步块
Java 同步块(synchronized block)用来标记方法或者代码块是同步的.Java 同步块用来避免竞争.本文介绍以下内容: Java 同步关键字(synchronzied) 实例方法同步 ...
- java多线程环境单例模式实现详解
Abstract 在开发中,如果某个实例的创建需要消耗很多系统资源,那么我们通常会使用惰性加载机制,也就是说只有当使用到这个实例的时候才会创建这个实例,这个好处在单例模式中得到了广泛应用.这个机制在s ...
- Java CAS同步机制 原理详解(为什么并发环境下的COUNT自增操作不安全): Atomic原子类底层用的不是传统意义的锁机制,而是无锁化的CAS机制,通过CAS机制保证多线程修改一个数值的安全性。
精彩理解: https://www.jianshu.com/p/21be831e851e ; https://blog.csdn.net/heyutao007/article/details/19 ...
- JAVA多线程Thread VS Runnable详解
要求 必备知识 本文要求基本了解JAVA编程知识. 开发环境 windows 7/EditPlus 演示地址 源文件 进程与线程 进程是程序在处理机中的一次运行.一个进程既包括其所要执行的指令,也 ...
- java多线程及线程安全详解
为什么要使用多线程: 单线程只能干一件事 而多线程可以同时干好多事(将任务放到线程里执行 效率高) 而所谓同时干并不是真正意义上的同时 只是(这里就叫CPU)cpu在每个线程中随机切换来执行 ...
- Java多线程之线程池详解
前言 在认识线程池之前,我们需要使用线程就去创建一个线程,但是我们会发现有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因 ...
随机推荐
- 经典灰鸽子lcx
方法1路由配置 在路由器配置 进入虚拟服务器 填入ip 端口 就可以了方法2内网域名解析想以前的花生客 科迈都有这项免费业务但现在基本不提供了如果那个网站还有内网解析的功能 大家一定要发上来哦方法3p ...
- 宣布发布全新的 Windows Azure 缓存预览版
全新 Windows Azure 缓存的预览版现已发布.此托管服务可以提供闪电般的数据访问速度,以帮助您构建更具可伸缩性.响应更快的应用程序. 详情如下: · 托管式缓存:这一全新的托管服务为需 ...
- SPOJ 7258 Lexicographical Substring Search(后缀自动机)
[题目链接] http://www.spoj.com/problems/SUBLEX/ [题目大意] 给出一个字符串,求其字典序排名第k的子串 [题解] 求出sam上每个节点被经过的次数,然后采用权值 ...
- gcc 的include path和lib path调整
`gcc -print-prog-name=cc1plus` -v `g++ -print-prog-name=cc1plus` -v ------------------------------ ...
- iOS面试题03-UI控件
UI控件面试题 1.怎么解决缓存池端的问题(cell) 回答:1.>OS中不存在缓存池的情况,因为通常我们iOS开发,对象都是在需要的时候才会创建, 有种常用的说话叫做懒加载,还有在UITabl ...
- Spring+Maven配置等问题
1. 在POM中使用 统一/指定/特定 的Spring版本号 <properties> <spring.version>4.1.6.RELEASE</spring.ver ...
- php平均拆分大文件为N个小文件
用PHP程序拆分大文件为N个小文件 /* 假设有文件data.log , 内容如下,行数很多,假设有上亿条数据,文件大小大概在800M左右 92735290 80334472 49114074 871 ...
- cocos2dx定时器
cocos2dx三种定时器的使用以及停止schedule,scheduleUpdate,scheduleOnce 首先,什么是定时器呢?或许你有时候会想让某个函数不断的去执行,或许只是执行一次,获取你 ...
- 01-C语言基本知识
目录: 一.C语言基本知识 二.C语言概述 回到顶部 一.C语言基本知识 1 语言背景 1946年,美国冯·诺依曼第一台计算机. 四大部分:中央处理器(控制器,运算器),存储器,输入设备,输出设备. ...
- C++ 面向对象学习2 构造方法
Date.h #ifndef DATE_H #define DATE_H class Date{ public: Date(,,);//自定义了构造方法 会覆盖掉默认的无参构造方法 void setD ...