前言:

  只要涉及到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. JS 图片放大镜

    今天练习一个小demo, 从本地读取图片, 然后实现类似淘宝放大镜的效果, 再加两个需求 1 .可以调节缩放比例,默认放大两倍 2 . 图片宽高自适应, 不固定宽高 话不多说先看效果: 原理:1, 右 ...

  2. Jmeter利用正则表达式提取器提取登录cookie供下一步使用

    最近在学Jmeter,遇到需要登录之后才能进行下一步操作的场景,网上查了各位大神的资料,东拼西凑总算是做好满足需求了,写一下经过和步骤吧. 一.正常调用 按正常流程添加线程组.HTTP请求(登录和添加 ...

  3. Java秋招面经大合集

    微信公众号[程序员江湖] 作者黄小斜,斜杠青年,某985硕士,阿里 Java 研发工程师,于 2018 年秋招拿到 BAT 头条.网易.滴滴等 8 个大厂 offer,目前致力于分享这几年的学习经验. ...

  4. javascript入门篇(四)

    Break 和 Continue 语句 break 它常用于跳出 switch() 语句, break 语句也可用于跳出循环.break 语句跳出循环后,会继续执行该循环之后的代码(如果有的话) co ...

  5. fab 菜单实现—圆形、半圆、扇形、直线、射线

    前段时间记录一下fab 菜单实现之前传-钟表表盘,今天终于弄正文了. 本文基于上篇文章的布局方式和位置计算,并参考35 Cool Floating Action Button Animations(h ...

  6. Spring Boot 入门(六):集成 treetable 和 zTree 实现树形图

    本篇文章是接着Spring Boot 入门(五):集成 AOP 进行日志管理写的,主要集成了树形图,在部门列表或者权限列表中,树形图经常被用上.主要是根据相应的 API 凭借 html 字符串 1.t ...

  7. Android 9.0适配遇到的问题1

    文章同步自javaexception 本周在适配Android 9.0,过程中碰到了小问题 问题1: SSL handshake timed out 解决办法: Android 9.0 开始,默认不允 ...

  8. vivo4.0系统怎么不ROOT激活Xposed框架的教程

    在越来越多应用室的引流,或业务操作中,大多数需要使用安卓的强大Xposed框架,前几天,我们应用室采购了一批新的vivo4.0系统,大多数都是基于7.0以上系统,大多数不能够刷入Root的su权限,即 ...

  9. centos7.3 kubernetes/k8s 1.10 离线安装 --已验证

    本文介绍在centos7.3使用kubeadm快速离线安装kubernetes 1.10. 采用单master,单node(可以多node),占用资源较少,方便在笔记本或学习环境快速部署,不适用于生产 ...

  10. .NET+PostgreSQL实践与避坑指南

    简介 .NET+PostgreSQL(简称PG)这个组合我已经用了蛮长的一段时间,感觉还是挺不错的.不过大多数人说起.NET平台,还是会想起跟它“原汁原味”配套的Microsoft SQL Serve ...