Java并发之synchronized使用
synchronized,是Java语言的关键字,读['siŋkrənaizd],当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码。
一、Java为何要使用synchronized?
线程的同步是为了防止多个线程访问一个数据对象时,对数据造成的破坏。为确保共享变量不会出现并发问题,通常会对修改共享变量的代码块用synchronized加锁,确保同一时刻只有一个线程在修改共享变量,从而避免并发问题。所以需要牢牢记住“共享”这两个字,只有共享资源的读写访问才需要同步化,如果不是共享资源,那么就没有同步的必要。
二、synchronized修饰范围
修饰实例方法 > 多个线程访问同一个实例的加锁方法时,会出现锁的竞争
修饰静态方法 > 多个线程访问类的加锁方法时,会出现锁的竞争
修饰代码块 > 多线程访问到同一个代码块时,会出现竞争的问题
三、synchronized同步锁对象
synchronized可以用来修饰方法或代码块,我们可以把获取的同步锁归为以下3种:
- 实例对象锁:修饰在普通方法上(非静态方法);在代码块中修饰this即synchronized(this)代码块
- 类对象锁:修饰在静态方法上;在代码块中修饰class即synchronized(X.class)代码块
- 同步块非当前实例对象锁:在代码块中修饰非当前实例对象,比如在X类中synchronized(对象a)的代码
对这3种不同的锁,使用相互之间不受影响,对于同一种锁,会出现锁的竞态条件。
四、synchronized同步锁使用
对于1.实例对象锁的使用:
- 所有的非静态同步方法用的都是同一把锁—实例对象本身,也就是说如果一个实例对象的非静态同步方法获取锁后,该实例对象的其他非静态同步方法必须等待获取锁的方法释放锁后才能获取锁。
- 实例对象锁存在于当前实例,不同的实例对象的锁相互之间不受影响。
- synchronized(this)代码块获取的是该实例对应的锁,与非静态的synchronized同步方法使用的是同一把锁,会出现锁的竞争。
- 实例锁和类对象锁没有影响,不会造成彼此阻塞。
对于2.类对象锁的使用:
- 对于静态同步方法,锁是针对这个类的,锁对象是该类的Class对象。
- 而所有的静态同步方法用的也是同一把锁——类对象本身,如果一个静态同步方法获取锁后,其他的静态同步方法都必须等待该方法释放锁后才能获取锁。
- 不管是同一个实例对象的静态同步方法之间,还是不同的实例对象的静态同步方法之间,他们都使用的是同一个类的对象锁,会出现锁的竞争。
- synchronized(X.class)代码块使用的是类Class的对象锁,与类中静态同步方法会出现锁的竞争。多个类中的synchronized(X.class)代码块也会出现锁的竞态条件。
对于3.同步块非当前实例对象锁的使用:
- 对于同步块,由于其对象锁是可以选择的,只有使用同一把锁的同步块之间才有着竞态条件。
- 同步锁的对象是基于实际对象而不是对象引用的,所以使用时特别注意,在锁的作用域中因改变实际对象引用从而引起锁的对象改变导致同步锁失去竞太条件。
五、synchronized使用小结
3.测试case代码
package com.test.synchroniz;
public class Service {
public Service(){
System.out.println("当前线程:" + Thread.currentThread().getName() + " 构造方法");
}
static{
System.out.println("当前线程:" + Thread.currentThread().getName() + " 静态代码块");
}
private Object object1 = new Object();
private Object object2 = new Object();
synchronized public static void printA(){
try{
System.out.println("当前线程:" + Thread.currentThread().getName() + Thread.currentThread().getId() +"在 " + System.currentTimeMillis() + " 进入方法A");
Thread.sleep(3000);
System.out.println("当前线程:" + Thread.currentThread().getName() + Thread.currentThread().getId() +"在 " + System.currentTimeMillis() + " 退出方法A");
}catch(Exception e){
System.out.println(e);
}
}
synchronized public void printB(){
try{
System.out.println("当前线程:" + Thread.currentThread().getName() + Thread.currentThread().getId() +"在 " + System.currentTimeMillis() + " 进入方法B");
Thread.sleep(3000);
System.out.println("当前线程:" + Thread.currentThread().getName() + Thread.currentThread().getId() +"在 " + System.currentTimeMillis() + " 退出方法B");
}catch(Exception e){
System.out.println(e);
}
}
public void printC(){
System.out.println("当前线程:" + Thread.currentThread().getName() + Thread.currentThread().getId() +"在 " + System.currentTimeMillis() + " 进入方法C");
try{
synchronized(object1){
System.out.println("当前线程:" + Thread.currentThread().getName() + Thread.currentThread().getId() +"在 " + System.currentTimeMillis() + "进入方法C--synchronized{X}");
Thread.sleep(3000);
System.out.println("当前线程:" + Thread.currentThread().getName() + Thread.currentThread().getId() +"在 " + System.currentTimeMillis() + " 退出方法C-synchronized{X}");
}
System.out.println("当前线程:" + Thread.currentThread().getName() + Thread.currentThread().getId() +"在 " + System.currentTimeMillis() + " 退出方法C");
}catch(Exception e){
System.out.println(e);
}
}
public void printD(){
System.out.println("当前线程:" + Thread.currentThread().getName() + Thread.currentThread().getId() +"在 " + System.currentTimeMillis() + " 进入方法D");
try{
synchronized(object2){
System.out.println("当前线程:" + Thread.currentThread().getName() + Thread.currentThread().getId() +"在 " + System.currentTimeMillis() + "进入方法D--synchronized{X}");
Thread.sleep(3000);
System.out.println("当前线程:" + Thread.currentThread().getName() + Thread.currentThread().getId() +"在 " + System.currentTimeMillis() + " 退出方法D-synchronized{X}");
}
System.out.println("当前线程:" + Thread.currentThread().getName() + Thread.currentThread().getId() +"在 " + System.currentTimeMillis() + " 退出方法D");
}catch(Exception e){
System.out.println(e);
}
}
public void printE(){
System.out.println("当前线程:" + Thread.currentThread().getName() + Thread.currentThread().getId() +"在 " + System.currentTimeMillis() + " 进入方法E");
try{
synchronized(this){
System.out.println("当前线程:" + Thread.currentThread().getName() + Thread.currentThread().getId() +"在 " + System.currentTimeMillis() + " 进入方法E--synchronized{this}");
Thread.sleep(3000);
System.out.println("当前线程:" + Thread.currentThread().getName() + Thread.currentThread().getId() +"在 " + System.currentTimeMillis() + " 退出方法E-synchronized{this}");
}
System.out.println("当前线程:" + Thread.currentThread().getName() + Thread.currentThread().getId() +"在 " + System.currentTimeMillis() + " 退出方法E");
}catch(Exception e){
System.out.println(e);
}
}
public static void printF(){
System.out.println("当前线程:" + Thread.currentThread().getName() + Thread.currentThread().getId() +"在 " + System.currentTimeMillis() + " 进入方法E");
try{
synchronized(Service.class){
System.out.println("当前线程:" + Thread.currentThread().getName() + Thread.currentThread().getId() +"在 " + System.currentTimeMillis() + " 进入方法F--synchronized{class}");
Thread.sleep(3000);
System.out.println("当前线程:" + Thread.currentThread().getName() + Thread.currentThread().getId() +"在 " + System.currentTimeMillis() + " 退出方法F-synchronized{class}");
}
System.out.println("当前线程:" + Thread.currentThread().getName() + Thread.currentThread().getId() +"在 " + System.currentTimeMillis() + " 退出方法F");
}catch(Exception e){
System.out.println(e);
}
}
public void printG(){
System.out.println("当前线程:" + Thread.currentThread().getName() + Thread.currentThread().getId() +"在 " + System.currentTimeMillis() + " 进入方法G");
try{
synchronized(Service.class){
System.out.println("当前线程:" + Thread.currentThread().getName() + Thread.currentThread().getId() +"在 " + System.currentTimeMillis() + " 进入方法G--synchronized{class}");
Thread.sleep(3000);
System.out.println("当前线程:" + Thread.currentThread().getName() + Thread.currentThread().getId() +"在 " + System.currentTimeMillis() + " 退出方法G-synchronized{class}");
}
System.out.println("当前线程:" + Thread.currentThread().getName() + Thread.currentThread().getId() +"在 " + System.currentTimeMillis() + " 退出方法G");
}catch(Exception e){
System.out.println(e);
}
}
}
package com.test.synchroniz; /**
* 0.synchronized同步方法、synchronized静态同步方法分别是用到的是实例锁,类锁,一个线程获取到synchronized同步方法的锁时,
* 另一线程依然可以进入synchronized静态同步方法(实例锁,类锁两者不同,相互不影响
* )
* 1.synchronized同步方法,synchronized(this)都是对象锁,对于其他线程调用synchronized同步方法,synchronized(this)呈阻塞状态 </br>
* 2.同一时间同一线程只有一个线程获取对象锁执行 </br>
*
* 1.synchronized(非this)对象锁,对于非this如果是同一对象,两个线程同时只有一个可以获取该锁 </br>
* 2.对象锁(synchronized同步方法 或 synchronized(this))、synchronized(非this)对象锁 两个线程同时执行,都可获得各自的锁 </br>
*
* 1.synchronized修饰static方法与synchronized(X.class)作用一样
*
* @author fugaoyang
*
*/
public class TestRun { public static void main(String[] args) throws Exception {
Service service = new Service();
Thread threadA = new Thread("A"){
@Override
public void run(){
service.printA();
}
}; Thread threadB = new Thread("B"){
@Override
public void run(){
service.printB();
}
}; Thread threadC = new Thread("C"){
@Override
public void run(){
service.printC();
}
}; Thread threadD = new Thread("D"){
@Override
public void run(){
service.printD();
}
}; Thread threadE = new Thread("E"){
@Override
public void run(){
service.printE();
}
}; Thread threadF = new Thread("F"){
@Override
public void run(){
service.printF();
}
}; Thread threadG = new Thread("G"){
@Override
public void run(){
service.printG();
}
}; threadA.start();
//threadB.start();
//threadC.start();
//threadD.start();
//threadE.start();
threadF.start();
threadG.start(); threadA.join();
threadF.join();
threadG.join();
}
}
Java并发之synchronized使用的更多相关文章
- 深入理解Java并发之synchronized实现原理
深入理解Java类型信息(Class对象)与反射机制 深入理解Java枚举类型(enum) 深入理解Java注解类型(@Annotation) 深入理解Java类加载器(ClassLoader) 深入 ...
- Java并发之synchronized
Java多线程同步关键词是常用的多线程同步手段.它可以修饰静态类方法,实例方法,或代码块.修饰static静态方法时是对整个类加锁. 一.实现原理 在JVM中对象内存分三块区域,对象头.实例数据.对齐 ...
- Java并发之synchronized关键字深度解析(二)
前言 本文继续[Java并发之synchronized关键字深度解析(一)]一文而来,着重介绍synchronized几种锁的特性. 一.对象头结构及锁状态标识 synchronized关键字是如何实 ...
- 《提升能力,涨薪可待》—Java并发之Synchronized
Synchronized简介 线程安全是并发编程中的至关重要的,造成线程安全问题的主要原因: 临界资源, 存在共享数据 多线程共同操作共享数据 而Java关键字synchronized,为多线程场景下 ...
- Java并发之Synchronized机制详解
带着问题阅读 1.Synchronized如何使用,加锁的粒度分别是什么 2.Synchronized的实现机制是什么 3.Synchronized是公平锁吗 4.Java对Synchronized做 ...
- Java并发之synchronized关键字深度解析(一)
前言 近期研读路神之绝世武学,徜徉于浩瀚无垠知识之海洋,偶有攫取吉光片羽,惶恐未领略其精髓即隐入岁月深处,遂急忙记录一二,顺备来日吹cow之谈资.本小系列为并发之亲儿子-独臂狂侠synchronize ...
- Java并发之synchronized关键字
上篇文章我们主要介绍了并发的基本思想以及线程的基本知识,通过多线程我们可以实现对计算机资源的充分利用,但是在最后我们也说明了多线程给程序带来的两种典型的问题,针对它们,synchronize ...
- Java并发之synchronized深入
一句话总结synchronized: JVM会自动通过使用monitor来加锁和解锁,保证了同时只有一个线程可以执行指定代码,从而保证了线程安全,同时具有可重入和不可中断的性质. 一.synchron ...
- java并发之synchronized详解
前言 多个线程访问同一个类的synchronized方法时, 都是串行执行的 ! 就算有多个cpu也不例外 ! synchronized方法使用了类java的内置锁, 即锁住的是方法所属对象本身. 同 ...
随机推荐
- select下拉框默认不能选择第一个选项的问题
如题,现在有个js的功能:用户选择下拉框的同时,把选择的下拉框显示出来.同时选择的不能有重复的.刚开始 使用的是 select的onchange事件: $("#liveType") ...
- 颜色矩原理及Python实现
原理 颜色矩(color moments)是由Stricker 和Orengo所提出的一种非常简单而有效的颜色特征.这种方法的数学基础在于图像中任何的颜色分布均可以用它的矩来表示.此外,由于颜色分布信 ...
- c# 修改winform中app.config的配置值
public bool ChangeConfig(string AppKey,string AppValue) { bool result = true; try { XmlDocument xDoc ...
- How to prepare system design questions in a tech interview?
http://blog.baozitraining.org/2014/09/how-to-prepare-system-design-questions.html 如何准备面试中的系统设计问题一直都是 ...
- 【Leetcode】【Medium】Construct Binary Tree from Inorder and Postorder Traversal
Given inorder and postorder traversal of a tree, construct the binary tree. Note:You may assume that ...
- ldconfig: /usr/lib/libpython2.6.so.1.0-gdb.py is not an ELF file - it has the wrong magic bytes at the start.
https://bugzilla.redhat.com/show_bug.cgi?id=562980
- yii2.0中解决post的400错误
不想用gii的表单自己写表单,但是又遇到了400错误,怎么解决?下面为你解答一下:
- c++ 读取文本问题
c++文本操作有以下三个方法 ifstream,ofstream,fstream 读取文本常用的方法如下 std::ifstream input; input.open(".log" ...
- c++11 多线程新特性学习 (1) 管理线程
1.基础介绍 c++11中,线程是通过std::thread对象来开始的,用法为 #include<thread> //必须包含的头文件 void do_work(){ std::cout ...
- 随滚动条滚动,始终处于屏幕的中间类似qq的浮动窗口 (能看到运动的过程)
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...