本地线程

本地线程-ThreadLocal

大憨熊 提交于 2020-01-22 07:40:18
线程本地存储是一个自动化机制,可以为使用相同变量的每个不同的线程都创建不同的存储。简单来说,就是对于某个变量,针对不同的线程存储不同的值。 实例: import java.util.Random; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; /** * @Description * @Author KToTo * @Date 2019/3/18 22:22 **/ public class ThreadLoaclVariableHolder { //创建一个全局的ThreadLocal对象 private static ThreadLocal<Integer> value = new ThreadLocal<Integer>(){ private Random random = new Random(47); //初始化方法,此处的Random相当于共享变量,为了使演示效果明显, //故将该初始化方法同步 protected synchronized Integer initialValue() { return random.nextInt(1000); } }; /

volatile之一--volatile不能保证原子性

家住魔仙堡 提交于 2020-01-22 05:44:04
目录: 《 Java并发编程之三:volatile关键字解析 转载 》 《 volatile之一--volatile不能保证原子性 》 《 Synchronized之一:基本使用 》 Java语言是支持多线程的,为了解决线程并发的问题,在语言内部引入了 同步块 和 volatile 关键字机制 在java线程并发处理中,有一个关键字volatile的使用目前存在很大的混淆,以为使用这个关键字,在进行多线程并发处理的时候就可以万事大吉。 Java语言是支持多线程的,为了解决线程并发的问题,在语言内部引入了 同步块 和 volatile 关键字机制。 synchronized 同步块大家都比较熟悉,通过 synchronized 关键字来实现,所有加上synchronized 和 块语句,在多线程访问的时候,同一时刻只能有一个线程能够用synchronized 修饰的方法 或者 代码块。 volatile 用volatile修饰的变量,线程在每次使用变量的时候,都会读取变量修改后的最的值。volatile很容易被误用,用来进行原子性操作。 下面看一个例子,我们实现一个计数器,每次线程启动的时候,会调用计数器inc方法,对计数器进行加一 执行环境——jdk版本:jdk1.6.0_31 ,内存 :3G cpu:x86 2.4G 复制代码 代码如下: public class Counter

java 垃圾回收总结

随声附和 提交于 2020-01-21 21:47:13
java与C,c++有很大的不同就是java语言开发者不需要关注内存信息,不会显式的直接操作内存,而是通过jvm虚拟机来实现。 java虚拟机运行的时候内存分配图如下图: jvm虚拟机栈:一个是线程独有的,每次启动一个线程,就创建一个jvm虚拟机栈,线程退出的时候就销毁。这里面主要保存线程本地变量名和局部变量值。 本地方法栈: 调用本地jni方法的时候而创建的。这里分配的jvm之外的内存空间。方法调用结束之后销毁。 pc寄存器 : 这个保存线程当前执行的字节码指令 堆:主要保存创建的对象。 方法区:保存class相关的信息。主要是class的一个内存结构信息 常量池:方法区的一部分,主要保存class内存结构中常量值 例如String值,public static final 类型的值 我们这里说的垃圾回收,主要是java虚拟机对堆内存区域的回收。 1 首先的问题是:jvm如何知道那些对象需要回收 ? 目前有两种算法 引用计数法 每个对象上都有一个引用计数,对象每被引用一次,引用计数器就+1,对象引用被释放,引用计数器-1,直到对象的引用计数为0,对象就标识可以回收 这个可以用数据算法中的图形表示,对象A-对象B-对象C 都有引用,所以不会被回收,对象B由于没有被引用,没有路径可以达到对象B,对象B的引用计数就就是0,对象B就会被回收。 但是这个算法有明显的缺陷

剑指Offer(JVM)——Java内存模型

廉价感情. 提交于 2020-01-21 18:44:41
文章目录 线程角度 1、程序计数器(Program Counter Register) 2、Java虚拟机栈(Stack) 3、本地方法栈(Native Stack) 4、元空间(MetaSpace)和永久代(PermGen)区别 5、堆(Heap) 首先来简单介绍一下内存: 程序执行过程中需不断的将逻辑地址和物理地址进行映射从而找到指令具体执行的位置。 Java程序运行在虚拟机上,运行时候需要内存空间,执行Java程序过程中JVM内部将整个JVM划分成不同的数据区域去管理。 C语言的编译器在划分区域时候将管理的区域划分成数据段和代码段。数据段分为堆、栈和方法区,Java中内存区域是如何划分的可以从 线程角度和模型角度 去分析一下: 线程角度 哪些是 线程私有 的区域哪些是 线程共享 的区域: 1、程序计数器(Program Counter Register) 程序计数器在Java内存中占据一段较小的内存模型。 当前线程所执行的字节码的行号指示器(逻辑)而非物理指示器; 改变计数器的值来选取下一条需要执行的字节码指令; 和线程是一对一的关系即" 线程私有 ",因为多线程需要通过轮换分配CPU资源去进行高效执行; 对Java方法计数,如果是Native方法计数器值为Undefined; 最重要的是不会发生内存泄露( 因为记录的仅仅是行号 )。

ThreadLocal原理分析与使用场景

穿精又带淫゛_ 提交于 2020-01-21 13:48:43
什么是ThreadLocal变量 ThreadLoal 变量,线程局部变量,同一个 ThreadLocal 所包含的对象,在不同的 Thread 中有不同的副本。这里有几点需要注意: 因为每个 Thread 内有自己的实例副本,且该副本只能由当前 Thread 使用。这是也是 ThreadLocal 命名的由来。 既然每个 Thread 有自己的实例副本,且其它 Thread 不可访问,那就不存在多线程间共享的问题。 ThreadLocal 提供了线程本地的实例。它与普通变量的区别在于,每个使用该变量的线程都会初始化一个完全独立的实例副本。ThreadLocal 变量通常被private static修饰。当一个线程结束时,它所使用的所有 ThreadLocal 相对的实例副本都可被回收。 总的来说,ThreadLocal 适用于每个线程需要自己独立的实例且该实例需要在多个方法中被使用,也即变量在线程间隔离而在方法或类间共享的场景。 ThreadLocal实现原理 首先 ThreadLocal 是一个泛型类,保证可以接受任何类型的对象。 因为一个线程内可以存在多个 ThreadLocal 对象,所以其实是 ThreadLocal 内部维护了一个 Map ,这个 Map 不是直接使用的 HashMap ,而是 ThreadLocal 实现的一个叫做 ThreadLocalMap

Executor框架

陌路散爱 提交于 2020-01-21 08:17:06
目录 Executor框架简介 Executor框架的结构与成员 Executor框架的结构 Executor框架的成员 ThreadPoolExecutor详解 FixedThreadPool详解 SingleThreadExecutor详解 CachedThreadPool详解 ScheduledThreadPoolExecutor详解 ScheduledThreadPoolExecutor的运行机制 ScheduledThreadPoolExecutor的实现 FutureTask详解 FutureTask简介 FutureTask的使用 FutureTask的实现 在Java中,使用线程来异步执行任务。Java线程的创建与销毁需要一定的开销,如果我们 为每一个任务创建一个新线程来执行,这些线程的创建与销毁将消耗大量的计算资源。同时, 为每一个任务创建一个新线程来执行,这种策略可能会使处于高负荷状态的应用最终崩溃。 Java的线程既是工作单元,也是执行机制。从JDK5开始,把工作单元与执行机制分离开 来。工作单元包括Runable和Callable, 而执行机制由Executor框架提供。 Executor框架简介 Executor框架的两级调度模型 在HotSpotVM的线程模型中, Java线程(java.lang. Thread)被一对一映射为本地操作系统线 程。

Java多线程-ThreadLocal详解

纵饮孤独 提交于 2020-01-21 05:32:32
文章目录 简介 例子 实现原理 常用方法详解 set方法 get方法 remove方法 ThreadLocal的作用 注意事项 总结 简介 ThreadLocal是JDK包提供的,它提供了线程本地变量,也就是如果你创建了一个ThreadLocal变量,那么访问这个变量的每个线程都会有这个变量的一个本地副本。当多个线程操作这个变量时,实际操作的是自己本地内存里面的变量,从而避免了线程安全问题。创建一个ThreadLocal变量后,每个线程都会复制一个变量到自己的本地内存。 简单说ThreadLocal就是一种以空间换时间的做法,在每个Thread里面维护了一个ThreadLocal.ThreadLocalMap,把数据进行隔离,每个线程的数据不共享,自然就没有线程安全方面的问题了. ThreadLocal可以实现每个线程绑定自己的值,即每个线程有各自独立的副本而互相不受影响。一共有四个方法:get, set, remove, initialValue。可以重写initialValue()方法来为ThreadLocal赋初值 例子 本例开启了两个线程,在每个线程内部都设置了本地变量的值,代码如下: public class ThreadLocalDemo { //创建ThreadLocal变量 static ThreadLocal<String> localParam = new

jvm gc 线程

非 Y 不嫁゛ 提交于 2020-01-20 20:48:06
java虚拟机运行时数据区 方法区 ​ 属于共享内存区域,存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。 java虚拟机: ​ 线程私有,生命周期和线程一致。描述的是 Java 方法执行的内存模型:每个方法在执行时都会床创建一个栈帧(Stack Frame)用于存储 局部变量表 、 操作数栈 、 动态链接 、 方法出口 等信息。每一个方法从调用直至执行结束,就对应着一个栈帧从虚拟机栈中入栈到出栈的过程。 StackOverflowError:线程请求的栈深度大于虚拟机所允许的深度。 OutOfMemoryError:如果虚拟机栈可以动态扩展,而扩展时无法申请到足够的内存。 本地方法栈 ​ 区别于 Java 虚拟机栈的是,Java 虚拟机栈为虚拟机执行 Java 方法(也就是字节码)服务,而本地方法栈则为虚拟机使用到的 Native 方法服务。也会有 StackOverflowError 和 OutOfMemoryError 异常。 java堆 ​ 对于绝大多数应用来说,这块区域是 JVM 所管理的内存中最大的一块。线程共享,主要是存放对象实例和数组。内部会划分出多个线程私有的分配缓冲区(Thread Local Allocation Buffer, TLAB)。可以位于物理上不连续的空间,但是逻辑上要连续。 程序计数器 内存空间小,线程私有

【性能调优】JNI内存溢出案例(String对象溢出)

亡梦爱人 提交于 2020-01-19 21:31:05
前言 场景:C++通过JNI将数据传输给Java程序 问题:运行一段时间String对象和Char字符不停变大,直到内存溢出(JVM-OOM) 1 过程 Jmap初步分析头部对象内存占用 PS:jmap -histo:live <pid>,执行该方法会同步执行一次GC,所以,展示的都是无法GC的对象。 发现:String对象有28万个,可能存在String对象被长期持有的现象,初步怀疑是HashMap等缓存持有 Jmap导出堆栈分析:导出堆栈时String对象是21万个 jmap -dump:live,format=b,file=/root/edr.bin 17994 用eclipse-mat打开堆栈文件:通过Histogram看看对象实例数 发现:String对象确实是21万个 看看String对象来自于哪里,并将String列表按RetainedHeap倒叙排列 发现:String对象是来自于本地JNI线程,且这个JNI线程还持有大量的内存 查看程序线程内存占用情况 发现:存在10个相似的线程,都占用了很多内存,且线程类型还是守护类型,但是无法通过线程名判断是什么线程对象 查看线程持有哪些对象 发现:线程持有14759个String对象,基本可以判断是该类(10个)线程没有将JNI-String内存释放 最终确认确实是C++JNI相关代码没有释放内存 2 总结

面试-Java多线程-3

别来无恙 提交于 2020-01-19 19:23:17
9. 线程面试 9.1什么是线程 线程是操作系统能进行运算调度的最小单位,可以使用多线程对运算密集型任务进行任务提速 9.2线程和进程区别 1) 线程是进程的子集,一个进程可以有多个线程,每条线程并行执行不同的任务。 2) 不同进程使用不同的内存空间,所有的线程共享一片相同的内存空间。 每个线程还拥有单独的栈内存用来存放本地数据 9.3java如何实现线程 1) 继承Thread类 2) 实现Runable接口 9.4用Runable还是Thread 如果类要实现多继承,那最好使用Runable 9.5Thread类的start和run的区别 1) start方法是被用来创建新线程,而start内部调用了run方法。 2) 如果直接调用run方法,只会在原来的线程中调用,没有启用新的线程 3) run() 方法用于执行线程的运行时代码。run() 可以重复调用,而 start() 只能调用一次 9.6java中Runable和Callable的区别 1) 两者都表示在不同线程中执行的任务。 2) Callbale的call方法可以返回值和抛出异常,并且可以返回装载有计算结果的Future对象 9.7java中的CycliBarrier和CountDownLatch 1)CountDownLatch和CyclicBarrier都能够实现线程之间的等待,只不过它们侧重点不同; 2