[Java并发编程之美]第2章 并发编程的其他基础知识 补充知识

synchronized与volatile关键字

一、 synchronized

synchronized是Java语法中的一个内置锁的实现。synchronized关键字解决了代码块或者方法上的同步问题,同一时间,只有一个线程能够通过并执行。保证线程安全:内存可见性和原子性提供了并发场景的一个共享资源访问的解决方案。
当我们说synchronized锁住的是一个JVM对象时,真正发挥作用的是对象头上所指向的monitor对象(监视器机制:Java锁的底层实现)。

synchronized有两种作用域:方法或代码块
1.作用域为方法:这种作用域下,锁住的对象为this,也就是当前对象;如果方法是静态的,锁住的是当前的Class类对象。

public synchronized void synchronizeMethod() {
    // do sth
}

2.作用域为代码块:锁住的对象为synchronized之后指定的对象,下例中即为resource。

public static void main() {
    synchronized(resource) {
        // do sth
    }
}

在真正执行的时候,两者都是会去获取底层monitor锁(监视器锁)执行。

二、volatile

volatile只能够用于修饰变量。
它能够保证的是,变量在程序执行过程中的可见性和有序性,它不能保证变量的原子性。
1、可见性,但不保证原子性:
第一,被volatile修饰的变量,一旦有修改,会立即刷新到主内存里面。
第二,被volatile修饰的变量,一旦被一个线程修改了,其他线程马上就能够读到这个变量修改后的值(即与主内存同步)。
它不能保证变量的原子性。它只是保障了变量在读/写操作的时候,具有原子性,但是无法保证变量在任何操作的时候是原子的。例如,在多线程的场景下,一旦有多个线程同时来执行i++,即使是使用volatile修饰的变量i,也是无法保证i++执行的正确性,因为涉及到读+写。

2、有序性:
关键在于多个内存读写操作有没有被CPU硬件以及编译器软件调换顺序。
以如下代码段为例,

//线程A
1. succ=false
2. i=10
3. doSomething()
4. i=20
5. succ = true

// 线程B
6. if (succ) {
7.     doSomethingB();
8. }

若succ未用volatile修饰,则可能的执行顺序为15234,succ提前置为true可能会造成线程B出现问题。
若succ使用volatile修饰,就会严格按照步骤1,中间步骤2~4,步骤5,来执行,这里面的中间步骤2~4顺序究竟如何,不用去管,但是它一定会等到中间步骤都执行完毕才去执行最后一个步骤。这就是volatile所保证的有序性。

三、synchronized与volatile关键字的理解

  • synchronized和volatile都是用于解决线程同步问题的java关键字,它们都能够一定程度上解决资源在多线程场景下的同步问题,单线程场景下,它们的优势发挥不出来,只能增加性能负担。
  • synchronized是一个重量级相对较高的锁操作,它占用的资源更多,性能更低,但是在多线程环境下更为安全,能够保证某段代码块只能只能够串行执行。其背后的原理,是Java利用Monitor锁机制,来实现对线程调度的控制。
  • volatile则是一个轻量级的操作,性能相对较好,但是性能要好上多少需要根据具体情况具体分析;它只能保证变量的可见性以及在代码执行中的有序性,并不能保障操作的原子性,也不能保证线程安全。
  • 使用volatile的场景:写入变量值不依赖变量的当前值。因为如果依赖当前值,则需要保证读+计算+写的原子性。

四、参考链接

https://bbs.byr.cn/#!article/Java/63393

原文地址:https://www.cnblogs.com/coding-gaga/p/12404148.html

时间: 2024-07-30 11:07:04

[Java并发编程之美]第2章 并发编程的其他基础知识 补充知识的相关文章

编程之美笔记--第一章游戏之乐--1.2中国象棋将帅问题

后来一版作者又将最后一句改为:”要求在代码中只能使用一个字节存储变量“. 我的解法: package android.zlb.java; /** * * @author zhanglibin * */ public class TestXiangqi { public static void main(String[] args) { for(int i = 11; i < 100; i++) { if(i / 10 % 3 == 1 && (i % 10 == 1 || i % 1

[Java并发编程之美]第1章 线程基础(待更新)

第1章 线程 线程与进程 进程是操作系统资源分配和调度的基本单位,但cpu资源是分配到线程的,也就是线程是CPU分配的基本单位. 线程自己的栈资源中,存放的局部变量是线程私有的,其他线程无法访问,除此之外栈还存线程的调用栈帧. 线程创建 三种方式:实现Runnable接口的run方法:继承Thread类并重写run方法:使用FutureTask方式. 线程等待与通知 1 wait() 线程先要事先获得共享变量上的监视器锁,然后当一个线程调用一个共享变量的wait()方法,该线程会被阻塞挂起,并且

编程之美第三章-字符串移位包含的问题

#include<iostream> #include<string> using namespace std; bool find_str(string s1,string s2) { if(s1.empty()||s2.empty()) return false; string::size_type pos=s1.find(s2); return (pos!=string::npos)?true:false; } int main() { string s1; cin>&

编程之美第三章-3.2-电话号码以及对应的单词

#include<iostream> #include<string> using namespace std; const int max_length=9; char c[10][10]={ "",//0 "",//1 "ABC",//2 "DEF",//3 "GHI",//4 "JKL",//5 "MNO",//6 "PQRS&

【编程珠玑】【第二章】编程求解组合问题

组合问题 以下两个题目是等价的: 题目1:输入一个字符串,输出该字符串中字符的所有组合.举个例子,如果输入abc,它的组合有空.a.b.c.ab.ac.bc.abc. 题目2:打印一个集合所有的子集和,比如{a,b,c}的子集和有{a},{b},{c},{a,b},{a,c},{b,c},{a,b,c}以及空集{}. 方法一.递归求解给定集合的全组合n!. 之前我们讨论了如何用递归的思路求字符串的全排列,同样,本题也可以用递归的思路来求字符串的全组合. 1.算法思路: 具有三个元素的集合{a,b

【编程珠玑】【第二章】编程求解最大公约数和最小公倍数

一.简介 两个整数的最大公约数是能够同时整除它们的最大的正整数.辗转相除法基于如下原理:两个整数的最大公约数等于其中较小的数和两数的相除余数的最大公约数.例如,252和105的最大公约数是21(252 = 21 × 12:105 = 21 × 5),因为252 ÷105 = 2......42,所以(105,42)是21.在这个过程中,较大的数缩小了,所以继续进行同样的计算可以不断缩小这两个数直至余数变为零.这时的除数就是所求的两个数的最大公约数. 由辗转相除法也可以推出,两数的最大公约数可以用

《编程之美》之如何控制CPU的暂用率固定在50%

<编程之美>第一章 让CPU暂用率听你指挥的粗糙实现,如何控制CPU的暂用率固定在50% #include <stdio.h> #include <Windows.h> #ifdef __cplusplus extern "C" { #endif #include <Powrprof.h> #ifdef __cplusplus } #endif #define GetCPUTickCount() __rdtsc() typedef str

第12章-Swing编程 --- Swing概述

(一)Swing概述 将Swing组件按功能来分: ->顶层容器: JFrame.JApplet.JDialog和JWindow ->中间容器: JPanel.JScrollPane.JSplitPane.JToolBar等 ->特殊容器:在用户界面上具有特殊作用的中间容器,如JInternalFrame.JRootPane.JLayeredPane和JDestopPane等 ->基本组件:实现人机交互的组件,如JButton.JComboBox.JList.JMenu.JSlid

编程之美之数独求解器的C++实现方法

编程之美的第一章的第15节,讲的是构造数独,一开始拿到这个问题的确没有思路, 不过看了书中的介绍之后, 发现原来这个的求解思路和N皇后问题是一致的, 但是不知道为啥,反正一开始确实没有想到这个回溯法,知道是用回溯法求解之后,问题就变得容易了很多. 这里我们不打算实现数独的构造,相反的,我们实现一个数独求解器,以后妈妈再也不用担心我的数独了. 当然求解器的思路和构造数独的思路一样,都是回溯法搜索,这里不再过多说明. 程序运行说明: 1.把待求解的数独数据放到in.txt文件中, 程序会自动读取他,