文档章节

原子性 - synchronized关键词

dotleo
 dotleo
发布于 06/25 00:12
字数 1307
阅读 11
收藏 0
点赞 0
评论 0

原子性概念

原子性提供了程序的互斥操作,同一时刻只能有一个线程能对某块代码进行操作。

原子性的实现方式

在jdk中,原子性的实现方式主要分为:

  • synchronized:关键词,它依赖于JVM,保证了同一时刻只能有一个线程对作用对象作用范围内进行操作。
  • Lock:代码层面的锁,依赖CPU指令,主要实现类ReentrantLock,之后再说。
  • atomic包:该包中提供了一些可以保证原子操作的类。

注意上面加粗内容,比较关键,后面会有讲解,着重理解

从性能上看,上面三个逐优,但各自又有不同。

  • synchronized是不可中断锁,适合竞争不激烈,可读性比较好。
  • Lock是可中断锁,多样化同步,竞争激烈时能维持常态。
  • atomic竞争激烈时能维持常态,比Lock性能好,但只能同步一个值。

synchronized的四种用法

  • synchronized修饰的代码块,作用于调用的对象
  • synchronized修饰的方法,作用于调用的对象
  • synchronized修饰的静态方法,作用于这个类的所有对象
  • synchronized修饰的类,作用于这个类的所有对象

synchronized修饰的代码块和修饰的方法

package cn.com.dotleo.sync;


import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * Created by liufei on 2018/6/24.
 */
public class Sync1 {

    public void test1(int x) {
        synchronized (this) {
            for (int i = 0; i < 10; i++) {
                System.out.println("["+ x + "]test1: " + i);
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }


    public static void main(String[] args) {
        final Sync1 sync = new Sync1();
        ExecutorService executorService = Executors.newCachedThreadPool();
        executorService.execute(new Runnable() {
            public void run() {
                sync.test1(1);
            }
        });

        executorService.execute(new Runnable() {
            public void run() {
                sync.test1(2);
            }
        });
    }
}

代码参见Sync1.java

上面代码中,主要体现了多线程下,同一个对象调用同步代码块。

运行结果:

[1]test1: 0
[1]test1: 1
[1]test1: 2
[1]test1: 3
[1]test1: 4
[1]test1: 5
[1]test1: 6
[1]test1: 7
[1]test1: 8
[1]test1: 9
[2]test1: 0
[2]test1: 1
[2]test1: 2
[2]test1: 3
[2]test1: 4
[2]test1: 5
[2]test1: 6
[2]test1: 7
[2]test1: 8
[2]test1: 9

由此结果可以看出,在多线程下,两个线程同时作用于一个对象时,该代码块被先抢到资源的进程执行结束后另一个线程才得以执行。

将主函数修改如下:


    public static void main(String[] args) {

        final Sync1 sync1 = new Sync1();
        final Sync1 syncNew = new Sync1();
        ExecutorService executorService = Executors.newCachedThreadPool();
        executorService.execute(new Runnable() {
            public void run() {
                sync1.test1(1);
            }
        });
        executorService.execute(new Runnable() {
            public void run() {
                syncNew.test1(2);
            }
        });


    }

代码参见Sync1.java

[1]test1: 0
[2]test1: 0
[1]test1: 1
[2]test1: 1
[1]test1: 2
[2]test1: 2
[1]test1: 3
[2]test1: 3
[1]test1: 4
[2]test1: 4
[1]test1: 5
[2]test1: 5
[1]test1: 6
[2]test1: 6
[1]test1: 7
[2]test1: 7
[1]test1: 8
[2]test1: 8
[2]test1: 9
[1]test1: 9

从结果中可以看出,对于两个线程分别调用两个对象时,并没有锁的出现,线程交叉执行并输出。

同理,synchronized关键词修饰方法也是如此,这里不再演示,代码参见Sync2.java

因此我们可以看出:

  • synchronized修饰的代码块,作用于调用的对象
  • synchronized修饰的方法,作用于调用的对象

synchronized修饰的静态方法和类

修饰静态方法:

package cn.com.dotleo.sync;


import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * Created by liufei on 2018/6/24.
 */
public class Sync3 {

    public static synchronized void test3(int x) {
        for (int i = 0; i < 10; i++) {
            System.out.println("["+ x + "]test3: " + i);
        }
    }

    public static void main(String[] args) {

        final Sync3 sync3 = new Sync3();
        final Sync3 syncNew = new Sync3();
        ExecutorService executorService = Executors.newCachedThreadPool();
        executorService.execute(new Runnable() {
            public void run() {
                sync3.test3(1);
            }
        });
        executorService.execute(new Runnable() {
            public void run() {
                syncNew.test3(2);
            }
        });
    }
}

代码参见Sync3.java

关于synchronized修饰静态方法和类不再演示两个线程调用同一个对象,因为那样肯定是加锁的顺序输出。

[1]test3: 0
[1]test3: 1
[1]test3: 2
[1]test3: 3
[1]test3: 4
[1]test3: 5
[1]test3: 6
[1]test3: 7
[1]test3: 8
[1]test3: 9
[2]test3: 0
[2]test3: 1
[2]test3: 2
[2]test3: 3
[2]test3: 4
[2]test3: 5
[2]test3: 6
[2]test3: 7
[2]test3: 8
[2]test3: 9

修饰静态类:

package cn.com.dotleo.sync;


import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * Created by liufei on 2018/6/24.
 */
public class Sync4 {

    public static void test4(int x) {
        synchronized (Sync4.class) {
            for (int i = 0; i < 10; i++) {
                System.out.println("["+ x + "]test4: " + i);
            }
        }

    }

    public static void main(String[] args) {

        final Sync4 sync4 = new Sync4();
        final Sync4 syncNew = new Sync4();
        ExecutorService executorService = Executors.newCachedThreadPool();
        executorService.execute(new Runnable() {
            public void run() {
                sync4.test4(1);
            }
        });
        executorService.execute(new Runnable() {
            public void run() {
                syncNew.test4(2);
            }
        });
    }
}

代码参见Sync4.java

[1]test4: 0
[1]test4: 1
[1]test4: 2
[1]test4: 3
[1]test4: 4
[1]test4: 5
[1]test4: 6
[1]test4: 7
[1]test4: 8
[1]test4: 9
[2]test4: 0
[2]test4: 1
[2]test4: 2
[2]test4: 3
[2]test4: 4
[2]test4: 5
[2]test4: 6
[2]test4: 7
[2]test4: 8
[2]test4: 9

从上面的两个示例中都可以看出,在两个线程调用一个类的不同对象时,仍然能保证原子性。

由此可见:

  • synchronized修饰的静态方法,作用于这个类的所有对象
  • synchronized修饰的类,作用于这个类的所有对象

特别强调:

synchronized不是方法申明的一部分,如果子类继承了父类的synchronized方法,除非子类不会有synchronized修饰的。

© 著作权归作者所有

共有 人打赏支持
dotleo
粉丝 12
博文 49
码字总数 50199
作品 0
天津
程序员
【多线程】volatile非原子的特性

一、前言: 上一遍博客中已经提及了volatile关键字虽然拥有了多个线程之间的可见性,但是却不具备同步性(也就是原子性),可以算的上是线程同步的轻量级实现,性能要比synchronized强很多,...

qq_26545305
01/25
0
0
【并发编程】volatile非原子的特性

一、前言: 上一遍博客中已经提及了volatile关键字虽然拥有了多个线程之间的可见性,但是却不具备同步性(也就是原子性),可以算的上是线程同步的轻量级实现,性能要比synchronized强很多,...

qq_26545305
01/25
0
0
关于Java里面多线程同步的一些知识

# 关于Java里面多线程同步的一些知识 对于任何Java开发者来说多线程和同步是一个非常重要的话题。比较好的掌握同步和线程安全相关的知识将使得我们则更加有优势,同时这些知识并不是非常容易...

欧阳海阳
07/13
0
0
java并发之原子性、可见性、有序性

原子性 原子性:即一个操作或者多个操作 要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行。 在Java中,对基本数据类型的变量的读取和赋值操作是原子性操作,即这些操作是不可...

王念博客
2016/04/30
2.3K
2
多线程学习笔记(十二)

volatile的作用是使变量在多个线程间可见 1.死循环 public class PrintInfo implements Runnable { } public class Run { PrintInfo printInfo = new PrintInfo();printInfo.printInfo();Sy......

scymore
2016/09/13
43
0
Java 多线程:关键字 synchronized 和 volatile

关键字volatile是线程同步的轻量级实现,所以volatile性能比synchronized要好,volatile智能修饰变量,而synchronized可以修饰方法以及代码块。随着JDK新版发布,synchronized关键字在执行效...

JianF
2016/12/16
16
0
线程安全到底是什么意思?

本文转发自Jason’s Blog,原文链接 http://www.jasongj.com/java/thread_safe/ 多线程编程中的三个核心概念 原子性 这一点,跟数据库事务的原子性概念差不多,即一个操作(有可能包含有多个...

李矮矮
2016/10/17
89
0
Java多线程之内存可见性

Java内存模型( JMM ) : 1) 所有的变量都存储在主内存中 2) 每个线程都有自己独立的工作内存, 里面保存该线程使用到的变量的副本 ( 主内存中该变量的一份拷贝 ) JMM 两条规定: 1) 线程对共享变...

wall--e
2016/05/07
174
1
Synchronized

1、JavaSE 1.6 之前都认为synchronized是重量级锁,但是1.6进行了各种优化操作,所以并不是想象中那么重了,虽然synchronized的地方使用Lock都能实现,但是synchronized用处还是很广泛。 2、...

learn_more
2016/08/27
25
0
浅谈Java并发编程系列(四)—— 原子性、可见性与有序性

Java内存模型是围绕着在并发过程中如何处理原子性、可见性和有序性这3个特征来建立的,我们来看下哪些操作实现了这3个特性。 原子性(atomicity): 由Java内存模型来直接保证原子性变量操作...

codershamo
2017/11/29
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

崛起于Springboot2.X之开发拦截器(21)

序言:几乎所有项目都需要拦截器,所以小伙伴们必须要掌握这门技术哦,不然只会mybaits增删改查那是实习生干的活呀。 1、创建拦截器类,implements HandlerInterceptor public class MyInce...

木九天
18分钟前
1
0
(转)SQL语句的执行顺序

(7) SELECT (8) DISTINCT <select_list> (1) FROM <left_table> (3) <join_type> JOIN <right_table> (2) ON <join_condition> (4) WHERE <where_condition> (5) GROUP BY <group_by_list> (......

Avner
28分钟前
0
0
1.14 救援模式

确保开机启动时连接镜像文件,如果是真机服务器,就需要:U盘或光盘镜像启动进入BIOS 不同主板进入bios按键不同,一般是F12或Esc 光标:移动到Boot(开机启动项) 减号移动:光标选中行,按-...

小丑鱼00
35分钟前
0
0
ES11-全文检索

高级别全文检索通常用于在全文本字段(如电子邮件正文)上运行全文检索。 他们了解如何分析被查询的字段,并在执行之前将每个字段的分析器(或search_analyzer)应用于查询字符串。 1.term查...

贾峰uk
38分钟前
0
0
java 复制对象有哪些方式

java 复制对象有哪些方式 Apache的 Common beanutils库 org.apache.commons.beanutils.BeanUtils.copyProperties(dest,origin); Springframework 的BeanUtil 依赖: <dependency> ......

黄威
54分钟前
2
0
jstack的简单使用

公司测试反应, 一个java应用的机器, 即使不做交易, cpu始终是30%多, 于是想到了jstack, 实践步骤记录一下: 1, 找出java应用的进程号 ps -ef|grep 应用名|grep -v grep 2, 找出pid下的cpu占用...

零二一七
今天
1
0
导入CSV文件就行数据整理分析

#-*-coding:utf-8-*-import csv,os,re,mathlocalPath=input("请输入所有群文件的根目录:") #所有QQ群文件的物理根目录路径def info(): info_dic=[] dirList=os.listdi...

Kefy
今天
5
0
CoreText进阶(六)-内容大小计算和自动布局

CoreText进阶(六)-内容大小计算和自动布局 其它文章: CoreText 入门(一)-文本绘制 CoreText入门(二)-绘制图片 CoreText进阶(三)-事件处理 CoreText进阶(四)-文字行数限制和显示更...

aron1992
今天
1
0
一个Unity高人的博客,涉猎范围很广,深度也很深。

https://blog.csdn.net/ecidevilin/article/list/

爽歪歪ES
今天
0
0
Spring Cloud Config-Git后端

EnvironmentRepository的默认实现使用Git后端,这对于管理升级和物理环境以及审核更改非常方便。要更改存储库的位置,可以在Config Server中设置“spring.cloud.config.server.git.uri”配置...

itcloud
今天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部