前言:

  只要涉及到Java并发那么我们就会考虑线程安全,实际上能够实现线程安全的方法很多,今天先介绍一下synchronized关键字,主要从使用,原理介绍

一、synchronized的使用方法

  1、修饰代码块:大括号括起来的代码,作用于调用的对象

  2、修饰方法:整个方法,作用于调用的对象

下面来演示代码,并且理解这两个使用的方法

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; public class SynchronizedExample {
//使用synchronized修饰代码块
public void test1(int j) {
synchronized(this){
for(int i=0;i<10;i++) {
System.out.println("test->"+j+"->"+i);
}
}
}
//使用synchronized修饰方法
public synchronized void test2(int j) {
for(int i=0;i<10;i++) {
System.out.println("test->"+j+"->"+i);
}
}
public static void main(String args[]) {
SynchronizedExample example1=new SynchronizedExample();
SynchronizedExample example2=new SynchronizedExample();
ExecutorService e=Executors.newCachedThreadPool();
e.execute(()->{
example1.test1(1);
});
e.execute(()->{
example2.test1(2);
});
}
}

  上面的代码演示了如何修饰代码块和方法。这里主要说“作用于调用的对象”如何理解。上面两个线程分别执行两个对象中的test1方法,结果是两个线程会结合在一起执行,这是因为调用的对象不同,一个是example1对象,另一个是example2对象。如果同时调用example1对象中的test1和test2方法,那么会先执行test1再执行test2。就是这时候只在调用的对象相同的时候才会实现同步操作。结果如下图

  3、修饰静态方法:整个静态方法,作用于所有对象

  4、修饰类:括号起来的部分,作用于所有对象

  

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; public class SynchronizedExample {
//使用synchronized修饰类
public void test1(int j) {
synchronized(SynchronizeExample.class){
for(int i=0;i<10;i++) {
System.out.println("test->"+j+"->"+i);
}
}
}
//使用synchronized修饰静态方法
public static synchronized void test2(int j) {
for(int i=0;i<10;i++) {
System.out.println("test->"+j+"->"+i);
}
}
public static void main(String args[]) {
SynchronizedExample example1=new SynchronizedExample();
SynchronizedExample example2=new SynchronizedExample();
ExecutorService e=Executors.newCachedThreadPool();
e.execute(()->{
example1.test1(1);
});
e.execute(()->{
example2.test1(2);
});
}
}

  当理解了上面两条,下面的结果就很显然了。这里有点不同就是使用synchronized修饰类和修饰方法块时,后面的一个为当前类,一个为this,this可以理解为当前类的实例化对象,所以只对当前调用的对象有加锁。而锁一个类则是锁了当前类的所有实例化对象。即作用范围不一样。

二、synchronized原理

上面我们只是介绍了一下synchronized关键字的使用方法。接下来就是底层实现原理的介绍。

1、执行synchronized代码块的三个步骤:

  (1)、线程尝试获得锁,如果获得就进入第二步,否则就加入等待队列,阻塞并等待唤醒

  (2)、执行synchronized修饰部分的代码块

  (3)、线程释放锁。如果等待队列上有等待的线程,从中取一个并唤醒,但是不一定是按顺序的,也就是不保证公平性

2、JVM中的synchronized底层实现

  JVM是基于进入和退出monitor对象来实现方法同步和代码块同步。对于代码块同步:任何对象都有一个monitor与之关联,当一个monitor被持有后就会处于锁定状态,当线程执行到monitorenter指令时,就会尝试获得对象的monitor所有权。而反映到上面步骤即尝试获得锁。而后执行代码,当遇到monitorexit指令后就会释放锁。所以monitorexit指令一般放在方法结束处和异常处。上述这些指令都是JVM中编译后自动放置的。平常写代码的时候并不需要。

3、为什么synchronized作用的是对象

  在上面的使用方法中基本上都说了synchronized作用于对象,无论是调用的对象还是所有对象。为什么是作用于对象而不是代码块呢?是因为synchronized用的锁是存在Java对象头里的

  synchronized代表重量级锁(其实JDK有对synchronized进行各种优化,所以性能上有所提升。并不是说重量级锁就不使用了。)所以synchronized锁的是对象而不是代码块。

4、synchronized的可重入性

  synchronized是可重入的。可重入是通过记录锁的持有线程和持有数量来实现。当被调用synchronized保护的代码时,检查对象是否被锁,如果是再检查当前线程锁定,如果还是,那么增加持有数量。也就是上面例子中当一个线程拿到example1的锁之后,在没有释放锁的时候再次请求example1的锁是可以一定可以拿到的。这时候在JVM中关联的计数器就会加一,就相当于该线程持有锁的数量加一。而后每次执行一次monitorexit指令就会数量减一。当计数器为0的时候才会使得该线程释放对象锁(这里一定要弄清是对象而不是代码块,线程持有的是一个对象)。

5、synchronized的内存可见性

  synchronized是保证内存可见性的。在释放锁的时候,所有写入都会写回内存,获得锁后,就会从内存中读最新数据。但是若只为了保证内存可见性,简易使用volatile这个更加轻量级的锁。

四、总结

  其实重点强调的就是synchronized虽然是包裹着一个代码块,但是作用的一定是一个对象。这里并不是说线程拿到这个对象,这个对象就会被锁住,里面的其他代码都不可执行。这里意思是两个或多个线程尝试获得synchronized修饰的同一个代码块或方法,才会引起锁竞争。但是由于有时候作用的只是当前的调用对象,所以其他对象访问的时候也会也不会引起锁竞争,具体看使用方法的第一个例子。更重要还是去理解JVM中加入的monitorenter指令和monitorexit指令,会对理解synchronized有非常重要的帮助。同时说一下,当子类继承父类的时候,没有重写父类的synchronized方法,那么使用的时候是直接使用父类的方法,所以会同步。但是如果重写了方法却没有加上synchronized修饰。那么就不会有同步操作。所以子类是不会继承父类的synchronized锁。

Java并发——synchronized关键字的更多相关文章

  1. 精通java并发-synchronized关键字和锁

    目前CSDN,博客园,简书同步发表中,更多精彩欢迎访问我的gitee pages synchronized关键字和锁 示例代码 public class MyThreadTest2 { public ...

  2. Java并发-Synchronized关键字

    一.多线程下的i++操作的并发问题 package passtra; public class SynchronizedDemo implements Runnable{ private static ...

  3. Java并发—synchronized关键字

    synchronized关键字的作用是线程同步,而线程的同步是为了防止多个线程访问一个数据对象时,对数据造成的破坏. synchronized用法 1. 在需要同步的方法的方法签名中加入synchro ...

  4. Java 多线程 —— synchronized关键字

    java 多线程 目录: Java 多线程——基础知识 Java 多线程 —— synchronized关键字 java 多线程——一个定时调度的例子 java 多线程——quartz 定时调度的例子 ...

  5. 从分布式锁角度理解Java的synchronized关键字

    分布式锁 分布式锁就以zookeeper为例,zookeeper是一个分布式系统的协调器,我们将其理解为一个文件系统,可以在zookeeper服务器中创建或删除文件夹或文件.设D为一个数据系统,不具备 ...

  6. java基础Synchronized关键字之对象锁

    java中Synchronized关键字之对象锁    当有多个线程对一个共享数据进行操作时,需要注意多线程的安全问题. 多线程的同步机制对资源进行加锁,使得在同一个时间,只有一个线程可以进行操作,同 ...

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

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

  8. java中synchronized关键字分析

    今天我们来分析一下java中synchronized关键字.首先来看一段java代码:(本地编译环境为mac,jdk1.8的环境) Demo.java package com.example.spri ...

  9. Java基础-synchronized关键字的用法(转载)

    synchronized--同步 顾名思义是用于同步互斥的作用的. 这里精简的记一下它的使用方法以及意义: 当synchronized修饰 this或者非静态方法或者是一个实例的时候,所同步的锁是加在 ...

随机推荐

  1. ALS交替最小二乘法总结

    摘要: 1.算法概述 2.算法推导 3.算法特性及优缺点 4.注意事项 5.实现和具体例子 6.适用场合 内容: 1.算法概述 ALS是alternating least squares的缩写 , 意 ...

  2. 深度学习与自动驾驶领域的数据集(KITTI,Oxford,Cityscape,Comma.ai,BDDV,TORCS,Udacity,GTA,CARLA,Carcraft)

    http://blog.csdn.net/solomon1558/article/details/70173223 Torontocity HCI middlebury caltech 行人检测数据集 ...

  3. Rest_framework Router 路由器(含SimplyRouter源码浅解)

    目录 Rest_framework Router 路由器 ViewSet结合Router,自动生成url. 将ViewSet注册到Router中,需要三个要素: 关于路由规则,细分有四类: rest_ ...

  4. git入门手册:git的基本安装,本地库管理,远程上传

    前言: git是分布式的版本库控制系统,它能方便你将自己的代码寄存于远程服务器上,从而实现集体合作开发.git有GUI 图形界面,然而使用终端命令仍是主流.以下基于Ubuntu系统操作git(其方式也 ...

  5. LDAP客户端在Windows环境的部署及配置

    ldap客户端配置安装目录的子目录C:\OpenLDAP\etc\openldap,编辑slapd.conf,修改密码,保存并关闭文件.rootdn           "cn=Manage ...

  6. 接触新的项目,构建时候报错:Failure to find io.netty:netty-tcnative:jar:${os.detected.classifier}:2.0.7.Final in

    详细信息如下: Failure to find io.netty:netty-tcnative:jar:${os.detected.classifier}:2.0.7.Final in http:// ...

  7. .NET Core 3.0-preview3 发布

    .NET Core 3.0 Preview 3已经发布,框架和ASP.NET Core有许多有趣的更新.这是最重要的更新列表. 下载地址 :https://aka.ms/netcore3downloa ...

  8. Linux 桌面玩家指南:01. 玩转 Linux 系统的方法论

    特别说明:要在我的随笔后写评论的小伙伴们请注意了,我的博客开启了 MathJax 数学公式支持,MathJax 使用$标记数学公式的开始和结束.如果某条评论中出现了两个$,MathJax 会将两个$之 ...

  9. Java地位被撼动?Java与JavaScript的趣事连载

    第一回 JavaScript的进攻 公元2014年,Java 第八代国王终于登上了王位. 第一次早朝,国王坐在高高的宝座上,看着毕恭毕敬的大臣,第一次体会到了皇权的威力. 德高望重的IO大臣颤悠悠地走 ...

  10. PHP全栈学习笔记6

    php能做什么,它是运行在服务器端的,web网站大部分数据都是存储在服务器上的,PHP就是用来处理这些存储在服务器的数据.跨平台,服务器可以是多种平台上的服务器,脚本语言,免费. wampserver ...