本文来自 图灵社区@fairjm

转截请注明出处

这个是书的笔记 书可以在safaribooksonline看,话说这个真的是一个很好的读外文书的网站啊,一个月39刀就可以畅想全站的书,很值。(订订订订订

因为是笔记所以觉得散不是你的错觉...因为本来就是散的...

笔记记录了一些概念 方便复习回顾的时候看 更多内容可以戳上面的链接

Scala的内存模型 多线程能力 和它的线程间同步全部继承自JVM

所有的抽象都有一定程度的泄漏 (all abstractions are to some extent leaky)

Processes and Threads

这通常是OS的任务:指派程序的执行部分给特定的处理器 - 这个机制被称为多任务,并且这对于计算机用户来说是透明的。

时间片(time slices)

一个进程是正被执行的计算机程序的实例。两个进程不能直接读取彼此的内存或者同时使用大部分的资源,使用多进程来表述多任务会非常麻烦 。

在同一个进程中互相独立的运算单元被称为线程。在典型的操作系统中,线程的数量比进程多得多。

每一个线程在程序运行时描述了当前的状态:通过程序栈和程序计数器。

当我们说程序执行了一个动作(比如向内存写入内容) 我们的意思是一个处理器执行了执行这个动作的线程。(注意这边的分句,我自己从onenote上粘贴上来都看了好几遍...)

OS线程是操作系统提供的编程设置 通常通过OS相关的编程接口来暴露出来被使用

在同一个进程中的分隔的线程共享同一区域的内存,通过读写内存来彼此交互。另一个来定义进程的方式是: 一系列的OS线程和这些线程共享的内存和资源。

系统周期性地指派不同的OS线程到CPU核心中来允许计算在所有处理器中进行。

java.lang.Thread Java的线程是直接映射到系统线程的 这意味着Java线程的行为是和OS线程是非常相似的

创建和启动线程

当JVM进程启动时 他默认会创建一些线程。最重要的线程是主线程(main thread) 执行程序的 main方法。这个线程的名字就叫main。

Thread的状态:

刚被创建时是 new

当被执行时是 runnable

结束执行是 terminated

启动一个独立的线程包含两步:

1 创建线程对象

2 用start方法执行

object ThreadsCreation extends App {

class MyThread extends Thread {

override def run(): Unit = {

println("New thread running.")

}

}

val t = new MyThread

t.start()

t.join()

println("New thread joined.")

}

join方法是中止main线程的运行直到t线程运行完毕

执行这个方法 将main线程转换到了 waiting 状态

等待的线程放弃了他的执行机会 OS可以将处理器用于其他的线程

注意: 等待的线程提醒OS它们正在等待某个状态并且 停止消耗 CPU周期 而不是重复地检查这个状态

sleep方法将线程放入 timed waiting 状态

OS同样可以将本该运行这个线程的处理器用来运行其他的线程

确定性: 特定的输入 程序总会产生相同的输出 而不管OS选择的执行调度有什么不同

由OS选择的调度不同而会对相同输出产生不同结果的称为 不确定性

大多数的多线程程序是非确定性的 这也是为什么多线程编程如此困难的原因

原子性执行(Atomic execution)

竞态条件(race condition) 是一种现象:并发程序的输出依赖于语句的执行调度。

不一定是不正确的行为。

但如果一些调度的结果是我们不预期的 那么这个竞态条件就可以考虑是一个程序错误

原子性执行:代码块的原子执行意味着代码中的语句不能由执行这段代码的线程和另一个执行这段代码的线程交错执行。

在原子性执行中 要么所要执行的代码都执行了 要么都没执行

可以通过同步块保证原子性:

def getUniqueId() = this.synchronized {

val freshUid = uidCount + 1

uidCount = freshUid

freshUid

}

在错误的对象上同步会造成比较难以找到的并发错误。

每一个JVM中创建的对象都会有一个特殊的实体成为内部锁(intrinsic lock)或者成为监视器(monitor) 用来保证只有一个线程可以执行在这个对象上的同步块

当T线程执行在x对象的同步块时 我们可以说 T线程获得了x的监视器的所有权。当线程执行完这个同步块 我们说他释放了这个监视器。

同步块语句是线程内通信的基本机制。无论何时,当多个线程要访问并修改在同一个对象中的字段时 你应该使用同步块。

重排序(reordering)

同步块也不是没有开销的

对字段进行写入将更加昂贵

同步块的性能损失程度取决于JVM实现 但通常不会很大

你可能会趋向于避免使用同步块当你觉得这里没有什么不好的语句交互执行的情况,比如上面那个例子一样(就是上面的代码没加同步块被多个线程访问)。永远不要这么做!(永远不要高估自己)

object ThreadSharedStateAccessReordering extends App {

for (i

var a = false

var b = false

var x = -1

var y = -1

val t1 = thread {

a = true

y = if (b) 0 else 1

}

val t2 = thread {

b = true

x = if (a) 0 else 1

}

t1.join()

t2.join()

assert(!(x == 1 && y == 1), s"x = $x, y = $y")

}

}

比如这个例子,我们的预期是0 0,10,0 1。1 1是我们所不预期的。

理论上不管我们运行多少次 永远不会有 x=1 y=1的情况发生(所以assert不会不成立 也就不会抛错)

但实际运行就会..

JVM允许重排序由一个线程执行的特定程序的语句 只要这个重排序不会改变这个线程的序列化执行语义。(the JVM is allowed to reorder certain program statements executed by one thread as long as it does not change the serial semantics of the program for that particular thread)

PS 这里简单说下:

a = true

y = if (b) 0 else 1

y = if (b) 0 else 1

a = true

对于序列化执行来说,这两个并没什么不同(不会产生不同的结果),所以这两个语句是可以重排序(不需要按照指令的执行顺序)

因为一些处理器不总是会按照程序的指令顺序执行

而且 线程也不需要将他们做的改动立马写入主存 而是暂时存在处理器的寄存器中缓存。这样可以最大化程序的运行效率并且允许更好的编译器优化。

以上的错误是我们假定线程中所有的写操作都可以立马被其他线程看到。我们需要应用一些合适的同步来确保一个线程修改被另一个线程看到的可见性。

同步块是其中一种实现这个可见性的同步方式。同步块不仅确保原子性也确保可见性。

java内存块_JVM上的并发和Java内存模型之同步块笔记相关推荐

  1. Java毕设项目线上教学平台(java+VUE+Mybatis+Maven+Mysql)

    Java毕设项目线上教学平台(java+VUE+Mybatis+Maven+Mysql) 项目运行 环境配置: Jdk1.8 + Tomcat8.5 + Mysql + HBuilderX(Webst ...

  2. Java 内存 关系_JVM和Linux之间的详细内存关系

    JVM和Linux之间的详细内存关系 在一些具有8g物理内存的服务器上,主要运行Java服务.系统内存分配如下:Java服务的JVM堆大小设置为6g,监视过程大约需要600m,Linux本身使用大约8 ...

  3. linux释放内存函数,LINUX上的getifaddrs()函数的内存释放有关问题

    LINUX上的getifaddrs()函数的内存释放有关问题 LINUX上的getifaddrs()函数的内存释放有关问题 日期:2014-05-16 浏览次数:20386 次 LINUX下的geti ...

  4. java 获取内存大小_JVM面试题扩展:Java代码在JVM中的执行流程

    代码示例: public class Test { // 常量 public static final String MAN_SEX_TYPE = "man"; // 静态变量 p ...

  5. JAVA开发(史上最完整追本溯源JAVA历史、发展和学习)

    (第二次世界大战1931-1945) 世界上最先进的技术往往是由于战争催生,在第二次世界大战中除了飞机,坦克和大炮的武器较量外,在隐秘战线的情报工作其实更为重要,在军队将领来往的电报中,为了防止军事情 ...

  6. java基础 第一章上(安装 配置java、简单dos命令)

    一.安装 配置java     下载安装          1.java官网下载jdk(32位或者64位根据自己电脑而定). 2.双击jdk.exe文件安装. 环境变量配置 右击我的电脑--属性--高 ...

  7. java阶梯算法_上楼梯算法的java实现(转)

    (java1.3.1下通过) import java.io.*; class upstair{ public static void main(String argc[]){ int n=Intege ...

  8. java多线程学习二、安全与不安全示例:12306买票和银行取钱、java内存模型、内存可见性、线程同步块和方法

    文章目录 前言 1. 什么是块,分为几种 2. 静态块与构造块的区别 一. 举例说明:并发情况下,线程不安全 1. 示例1:unsafe12306取票 2. 示例2:unsafe银行取钱 二.线程不安 ...

  9. java基础提升篇:synchronized同步块和volatile同步变量

    初遇 Java语言包含两种内在的同步机制:同步块(或方法)和 volatile 变量.这两种机制的提出都是为了实现代码线程的安全性.其中 Volatile 变量的同步性较差(但有时它更简单并且开销更低 ...

最新文章

  1. 【 MATLAB 】使用 MATLAB 求某输入的稳态响应
  2. 1.3 机器学习基础-深度学习第二课《改善深层神经网络》-Stanford吴恩达教授
  3. PyQt、QtDesigner及其它工具包的安装
  4. linux 应用层gpio中断_如何在嵌入式Linux中检测GPIO线路上的中断?
  5. BZOJ2647 : [Neerc2011]Journey
  6. 一款基于.NET Core的认证授权解决方案-葫芦藤1.0开源啦
  7. mysql update column_MySQL8.0 新特性:Partial Update of LOB Column
  8. mongdb group聚合操作
  9. UINavigationBar UINavigationItem UIBarButtonItem
  10. 记TensorFlow项目开源一周年
  11. ffmpeg time_base详解
  12. [Android] View控件显示隐藏动画效果
  13. 如何判断等保测评机构有资质?符合要求?
  14. Terminal Emulator for Android(安卓终端模拟器)的使用
  15. 暖通工程师有几个级别,以及注册暖通工程师挂靠价格
  16. echarts二次渲染时宽高为0图表不显示
  17. python wechat_wechat-sdk
  18. Bilibili批量取消关注
  19. 简明易懂的JVM垃圾回收理解
  20. 三网融合不可忽视的互联网力量

热门文章

  1. 深度学习之常见tricks
  2. 分类器是如何做检测的?(1)——CascadeClassifier中的detectMultiScale函数解读
  3. 《深入理解Java虚拟机》笔记3——7种垃圾收集器
  4. Java设计模式透析之 —— 策略(Strategy)
  5. Spark机器学习库(MLlib)指南
  6. LaTeX 笔记:NFSS 那点事儿
  7. ROS探索总结(十六)(十七)(十八)(十九)——HRMRP机器人的设计 构建完整的机器人应用系统 重读tf 如何配置机器人的导航功能
  8. ExtJs、ASP.net运用Linq to SQL与SQL储存过程交互
  9. MIT自然语言处理第二讲:单词计数(第一、二部分)
  10. 深度学习材料:从感知机到深度网络A Deep Learning Tutorial: From Perceptrons to Deep Networks