本地线程

Java多线程(5)

风格不统一 提交于 2020-01-19 18:35:07
Java多线程(5) CPU缓存一致性问题 因为缓存的出现,极大提高了CPU的吞吐能力,但同时也引入了缓存不一致的问题,比如i++操作 在程序运行过程,首先将主存中的数据复制一份存放到CPU Cache中,那么CPU寄存器进行数值计算的时候就直接到Cache中读取和写入,当整个运算过程完毕之后再讲Cache中的数据刷新到主存当中 具体如下: 读取主内存的i到cpu cache 对i进行+1操作 将结果写回到cpu cache中 将数据刷新到主内存 i++在单线程环境不会有什么问题,但在多线程下就会出现问题了 每个线程都有自己的工作内存,变量i会在多个线程的本地内存中都保存一个副本,如果同时两个线程执行i++操作,假设i的初始值为0,每一个线程都从主内存中获取i的值存入cpu cache,然后经过计算再写入主内存,很有可能i在经过了两次自增之后结果还是1,这就是典型的缓存不一致的问题 Java内存模型决定了一个线程对共享变量的写入何时对其他线程可见,Java内存模型定义了线程和主内存之间的抽象关系: 共享变量存储在主内存,每个线程都可以访问 每个线程都有私有的工作内存或者称为本地内存 工作内存只存储该线程对共享变量的副本 线程不能直接操作主内存,只有先操作了工作内存之后才能写入主内存 并发编程的三个重要特性 原子性 指在一次的操作或者多次操作中

java整个理解

浪尽此生 提交于 2020-01-19 18:19:31
jvm内存模型 堆内存 方法区 程序计数器 Java虚拟机栈 本地方法栈 运行时常量池 直接内存 **** 堆内存 这是jvm中最大的一块区域,基本上所有的变量和对象实例都在这一块区域存放,所有线程共享的。但是随着jdk1.6的发布,JIT即时编译技术的优化、逃逸分析技术的成熟,所有对象在堆上分配也不是那么绝对的,只要逃逸分析出对象不会逃逸出线程或者栈,那么原来在堆上分配的变量可以直接在栈上分配,这样在方法调用结束、或者线程结束的时候,栈上内存自动释放,可以大大减少堆内存上的GC收集,提高jvm整体运行效率。会抛出OutOfMemeryError错误,堆的生命周期和jvm的生命周期相同,随着JVM的启动而产生,JVM的终止而释放 **** 方法区 这一部分也是所有线程共享的。方法区存放的是类信息、常量、静态变量和即时编译器编译后的代码,方法区也叫永久代,这里存放的都是类相关的信息,还有字符变量和引用变量。会抛出OutOfMemeryError错误,生命周期和JVM相同 **** Java虚拟机栈 这一部分是线程私有的,每一个线程都会有一个虚拟机栈,虚拟机栈是Java方法执行的内存模型,每一个方法都在虚拟机栈中都对应一个栈帧,该栈帧存放的是,方法调用需要使用到的局部变量表(8大基本数据类型和reference对象引用)、方法参数、动态链接、操作数栈、方法出口的信息。Java没有c、c

JAVA多线程(十)Java多线程之ThreadLocal

冷暖自知 提交于 2020-01-19 03:53:05
1.JAVA多线程(十)Java多线程之ThreadLocal 1.1 ThreadLocal类    ThreadLocal类主要解决的就是让每个线程绑定自己的值,可以将ThreadLocal类形象的比喻成存放数据的盒子,盒子中可以存储每个线程的私有数据。 如果你创建了一个ThreadLocal变量,那么访问这个变量的每个线程都会有这个变量的本地副本,这也是ThreadLocal变量名的由来。他们可以使用 get()和 set())方法来获取默认值或将其值更改为当前线程所存的副本的值,从而避免了线程安全问题。 每个线程往ThreadLocal中读写数据是线程隔离,互相之间不会影响的,由于不需要共享信息,自然就不存在竞争问题了,从而保证了某些情况下线程的安全,以及避免了某些情况需要考虑线程安全必须同步带来的性能损失! 1.2 ThreadLocal示例 package com . yuanxw . chapter10 ; import java . util . Random ; /** * ThreadLocal * 线程局部变量 */ public class ThreadLocalExample { private static ThreadLocal < String > defaultThreadLocal = new ThreadLocal ( ) {

Volatile总结

吃可爱长大的小学妹 提交于 2020-01-18 23:45:31
在java线程并发处理中,有一个关键字volatile的使用目前存在很大的混淆,以为使用这个关键字,在进行多线程并发处理的时候就可以万事大吉。 Java语言是支持多线程的,为了解决线程并发的问题,在语言内部引入了 同步块 和 volatile 关键字机制。 synchronized 同步块大家都比较熟悉,通过 synchronized 关键字来实现,所有加上synchronized 和 块语句,在多线程访问的时候,同一时刻只能有一个线程能够用 synchronized 修饰的方法 或者 代码块。 volatile 用volatile修饰的变量,线程在每次使用变量的时候,都会读取变量修改后的最的值。volatile很容易被误用,用来进行原子性操作。 意思就是说,如果一个变量加了volatile关键字,就会告诉编译器和JVM的内存模型:这个变量是对所有线程共享的、可见的,每次jvm都会读取最新写入的值并使其最新值在所有CPU可见。 volatile似乎是有时候可以代替简单的锁,似乎加了volatile关键字就省掉了锁。但又说volatile不能保证原子性(java程序员很熟悉这句话:volatile仅仅用来保证该变量对所有线程的可见性,但不保证原子性) 。这不是互相矛盾吗? 1.Volatile不具有原子性 2.告诉jvm该变量为所有线程共享的,Cpu执行时不进行线程间上下文环境切换

二、JVM之体系结构

蹲街弑〆低调 提交于 2020-01-18 18:48:21
JVM体系结构图 Native Interface(本地接口) Java本地接口(Java Native Interface (JNI))允许运行在Java虚拟机(Java Virtual Machine (JVM))上的代码调用本地程序和类库,或者被它们调用,这些程序和类库可以是其它语言编写的,比如C、C++或者汇编语言。 Program Counter Register(程序计数器) 每个线程都有一个程序计数器,是线程私有的,就是一个指针,指向方法区中的方法字节码(用来存储指向下一条指令的地址),由执行引擎读取下一条指令,是一个非常小的内存空间,几乎可以忽略不计。 这块n内存区域很小,它是当前线程所执行的字节码的行号指示器,字节码解释器通过改变这个计数器的值来选取下一条需要执行的字节码指令。如果是一个native方法,那么这个计数器就是空的。因为native方法是java通过JNI直接调用本地C/C++库,可以近似的认为native方法相当于C/C++暴露给java的一个接口,java通过调用这个接口从而调用到C/C++方法。由于该方法是通过C/C++而不是java进行实现。那么自然无法产生相应的字节码,并且C/C++执行时的内存分配是由自己语言决定的,而不是由JVM决定的。 Native Method Stack(本地方法栈) 本地方法栈的功能和特点类似于虚拟机栈

JVM 线程中方法执行过程

倖福魔咒の 提交于 2020-01-18 09:56:23
本章节内容参考:《深入理解Java虚拟机》 运行时数据区: 本次只介绍用于程序运行的线程私有的内存模型。 虚拟机栈(FILO):java方法执行的内存模型。   栈帧(线程执行的一个方法的内存模型,每调用一个方法,压入一个栈帧)    局部变量表:编译器可知的8种基本类型、reference类型、returnAddress类型   操作数栈:一个用于计算的临时数据存储区(明显,此栈是为了存放要操作的数据用的)    动态链接:支持java多态   返回地址:方法结束的地方。return/Exception 本地方法栈:Native方法执行的内存模型。 程序计数器:这个计数器记录的是正在执行的虚拟机字节码指令的地址(如果线程正在执行的是一个java方法)。 字节码解释器工作时,就是通过改变这个计数器的值来选取需要执行的字节码 指令(分支,循环,跳转、异常处理、线程恢复) 线程中,方法A调用方法B。 线程的执行的过程:    1、线程开始,分配虚拟机栈大小(JVM参数 -Xss:大小,1.5+默认1M), 2、执行方法A时,创建一个栈帧A压入虚拟机栈顶,根据程序计数器中的记录的下一个要执行的字节码指令的地址,找到并执行指令(将要操作的数据压入操作数栈栈顶,将操作结果放入局部变量表中,详细过程参照下面“合代码演示”部分)。 3、中间调用方法B,则创建栈帧B,接着执行方法B的指令

1、jvm概述

无人久伴 提交于 2020-01-18 04:36:36
图片源于网络 大多数 JVM 将内存区域划分为 Method Area(Non-Heap)(方法区), Heap(堆), Program Counter Register(程序计数器) , VM Stack(虚拟机栈,也有翻译成JAVA 方法栈的), Native Method Stack ( 本地方法栈 ), 其中 Method Area 和 Heap 是线程共享的 ,VM Stack,Native Method Stack 和Program Counter Register 是非线程共享的。为什么分为线程共享和非线程共享的呢?请继续往下看。 首先我们熟悉一下一个一般性的 Java 程序的工作过程。一个 Java 源程序文件,会被编译为字节码文件(以 class 为扩展名),每个java程序都需要运行在自己的JVM上,然后告知 JVM 程序的运行入口,再被 JVM 通过字节码解释器加载运行。那么程序开始运行后,都是如何涉及到各内存区域的呢? 概括地说来,JVM初始运行的时候都会分配好 Method Area(方法区) 和Heap(堆) ,而JVM 每遇到一个线程,就为其分配一个 Program Counter Register(程序计数器) , VM Stack(虚拟机栈)和Native Method Stack (本地方法栈) 当线程终止时,三者(虚拟机栈

6.synchronized

半腔热情 提交于 2020-01-17 06:08:15
文章目录 1. 锁的升级 1.1. 偏向锁 1.2. 轻量级锁 1.3. 重量级锁 2. 锁与可见性(内存刷新) Java 中的每一个对象都可以作为锁。具体表现为以下3种形式。 对于普通同步方法,锁是当前实例对象。 对于静态同步方法,锁是当前类的 Class 对象。 对于同步方法块,锁是 Synchonized 括号里配置的对象。 1. 锁的升级 1.1. 偏向锁 偏向 的意思是,偏向锁假定将来只有第一个申请锁的线程会使用锁(不会有任何线程再来申请锁),这是一中乐观锁策略 加锁 只需要在Mark Word中CAS记录owner(本质上也是更新,但初始值为空),如果记录成功,则偏向锁获取成功,记录锁状态为偏向锁,以后当前线程等于owner就可以零成本的直接获得锁. 锁膨胀 在退出同步块时不会释放锁。只有在第二个线程过来产生竞争的时候才会在 全局安全点 进行释放或者膨胀为轻量锁的操作。 锁撤销 偏向锁的撤销,需要等待全局安全点(在这个时间点上没有正在执行的字节码)。它会首先暂停拥有偏向锁的线程,然后检查持有偏向锁的线程是否活着,如果线程不处于活动状态,则将对象头设置成无锁状态;如果线程仍然活着,拥有偏向锁的栈会被执行,遍历偏向对象的锁记录,栈中的锁记录和对象头的 Mark Word 要么重新偏向于其他线程,要么恢复到无锁或者标记对象不适合作为偏向锁,最后唤醒暂停的线程. 批量再偏向

ThreadLocal原理分析

谁都会走 提交于 2020-01-16 09:58:17
ThreadLocal简介 ThreadLocal线程本地变量的副本,对一个线程内的变量的修改不影响其它线程的变量。即在多线程环境下,可以保证各个线程之间的变量互相隔离、相互独立。 ①ThreadLocal实例通常在类中被定义为private static ②ThreadLocal在线程的生命周期内起作用 ③空间换时间的设计思想 ThreadLocal用法 首先了解下ThreadLocal的基本用法 private static ThreadLocal<Map<String, String>> threadLocal = new MyThreadLocal(); private static class MyThreadLocal extends ThreadLocal<Map<String, String>>{ @Override protected Map<String, String> initialValue() { Map map = new HashMap<String, String>(); map.put("andy","18"); return map; } } public static void main(String[] args) { Map<String, String> result = threadLocal.get(); System.out

ThreadLocal源码分析

空扰寡人 提交于 2020-01-16 07:28:18
目录 ThreadLocal源码分析 简单分析 什么是ThreadLocal 大致实现思路 使用场景 源码分析 ThreadLocalMap ThreadLocal 参考博客 ThreadLocal源码分析 简单分析 什么是ThreadLocal ThreadLocal顾名思义可以理解为线程本地变量。也就是说如果定义了一个ThreadLocal,每个线程往这个ThreadLocal中读写是线程隔离(也就是每个线程读写都是自己的一份独立对象,与其他线程是无关的,当然前提是不同线程set的不是同一个对象的引用),互相之间不会影响的。它提供了一种将可变数据通过每个线程有自己的独立副本从而实现线程封闭的机制。 大致实现思路 Thread类有一个类型为ThreadLocal.ThreadLocalMap的实例变量threadLocals,也就是说每个线程有一个自己的ThreadLocalMap。ThreadLocalMap有自己的独立实现,可以简单地将它的key视作为ThreadLocal,value为代码中放入的值(实际上key并不是ThreadLocal本身,而是他的一个人弱引用)。每个线程在往某个ThreadLocal里赛值得时候,都会往自己的ThreadLocalMap里存,读也是以某个ThreadLocal作为引用,在自己的map里找对应的key,从而实现了线程隔离。 使用场景 1