本地线程

线程本地存储及实现原理

末鹿安然 提交于 2020-01-24 21:10:54
本文是《go调度器源代码情景分析》系列 第一章 预备知识的第十小节,也是预备知识的最后一小节。 线程本地存储又叫线程局部存储,其英文为Thread Local Storage,简称TLS ,看似一个很高大上的东西,其实就是线程私有的全局变量而已。 有过多线程编程的读者一定知道,普通的全局变量在多线程中是共享的,一个线程对其进行了修改,所有线程都可以看到这个修改,而线程私有的全局变量与普通全局变量不同,线程私有全局变量是线程的私有财产,每个线程都有自己的一份副本,某个线程对其所做的修改只会修改到自己的副本,并不会修改到其它线程的副本。 下面用例子来说明一下多线程共享全局变量以及线程私有全局变量之间的差异,并对gcc的线程本地存储做一个简单的分析。 首先来看普通的全局变量 #include <stdio.h> #include <pthread.h> int g = 0; // 1,定义全局变量g并赋初值0 void* start(void* arg) {   printf("start, g[%p] : %d\n", &g, g); // 4,子线程中打印全局变量g的地址和值   g++; // 5,修改全局变量   return NULL; } int main(int argc, char* argv[]) {   pthread_t tid;   g = 100; // 2

java volatitle 多线程问题

柔情痞子 提交于 2020-01-24 08:56:12
我们知道,在Java中设置变量值的操作,除了long和double类型的变量外都是原子操作,也就是说,对于变量值的简单读写操作没有必要进行同步。 这在JVM 1.2之前,Java的内存模型实现总是从主存读取变量,是不需要进行特别的注意的。而随着JVM的成熟和优化,现在在多线程环境下 volatile关键字的使用变得非常重要。在当前的Java内存模型下,线程可以把变量保存在本地内存(比如机器的寄存器)中,而不是直接在主存中进行 读写。这就可能造成一个线程在主存中修改了一个变量的值,而另外一个线程还继续使用它在寄存器中的变量值的拷贝,造成数据的不一致。要解决这个问题,只需 要像在本程序中的这样,把该变量声明为volatile(不稳定的)即可,这就指示JVM,这个变量是不稳定的,每次使用它都到主存中进行读取。一般说 来,多任务环境下各任务间共享的标志都应该加volatile修饰。 Volatile修饰的成员变量在每次被线程访问时,都强迫从共享内存中重读该成员变量的值。而且,当成员变量发生变化时,强迫线程将变化值回写到共享内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。 Java语言规范中指出:为了获得最佳速度,允许线程保存共享成员变量的私有拷贝,而且只当线程进入或者离开同步代码块时才与共享成员变量的原始值对比。 这样当多个线程同时与某个对象交互时

理解什么是线程安全性、原子性

只愿长相守 提交于 2020-01-24 08:47:08
目录 •写在前面 •原子性 加锁机制 •写在前面 进程想要执行任务需要依赖线程,换句话说就是进程中的最小执行单位就是线程,并且一个进程中至少有一个线程。提到多线程这里要说两个概念,就是串行和并行,搞清楚这个我们才能更好的理解多线程。所谓串行其实是相对于单条线程来执行多个任务来说的,我们就拿下载文件来举个例子,我们下载多个文件,在串行中它是按照一定的顺序去进行下载的,也就是说必须等下载完A之后,才能开始下载B,它们在时间上是不可能发生重叠的。 要编写线程安全的代码,其核心在于要对状态访问操作进行管理,特别是对共享的和可变的状态的访问。要是的对象是线程安全的,需要采用同步机制来协同对对象可变状态的访问,如果无法实现协同,那么可能会导致数据破坏以及其他不该出现的结果。java中的同步机制是关键字synchronized,它提供了独占式的加锁方式,不仅如此还包括volatile类型变量,显式锁Lock以及原子变量。 单线程近似定义为“所见即所知”,那么定义线程安全性,则当多个线程访问某个类时,这个类始终都能表现出正确的行为,那么就称这个类是线程安全的。一个类在单线程中运行都不正确,那么它肯定是不会是线程安全的。如果正确的实现了某个对象,那么在任何操作中(包括调用对象的公有方法或者对其公有域进行读写操作)都不会违背不变性条件或后验条件

进程和线程

你。 提交于 2020-01-24 02:50:38
1. 进程: (1)进程模型:一个进程就是一个程序的执行实例,程序是静态的,进程是动态的。一个进程有一个地址空间和一个控制线程,其中地址空间包含有:程序计数器、寄存器、变量的当前值。当一个进程被挂起时,进程的物理程序计数器值被保存在该进程的程序计数器中。下次进程运行时,再从程序计数器中取出计数值装入内存的程序计数器中。 (2)进程的创建:在unix系统中,创建新进程的方式只有一个:fork()函数,即创建一个子进程。子进程是父进程的一个副本,和父进程拥有相同的存储映像、相同的环境字符串和相同的打开文件。但是,子进程和父进程有各自不同的地址空间,不同的PID。通过系统调用execve()函数,可以替换地址空间中的程序段。( ps:子进程和父进程拥有不同的地址空间,但地址空间中的内容相同 ) (3)进程的三种状态:运行态、就绪态、阻塞态。( ps:系统调用pause()可以使进程进入阻塞态 ) (4)多进程的实现:操作系统维护着一张进程表,每个进程占用一个表项。该表项包含着进程状态的重要信息,包括:寄存器、程序计数器、堆栈指针、内存分配状况、打开文件的状态、调度信息、从运行态转为就绪态或阻塞态时所保存的信息(程序计数器值和寄存器中的相关信息)。当内核切换进程时,会将旧进程的信息装入进程表,保证下次该进程能正确启动,然后载入新进程的程序计数器和寄存器等相应信息到内存中,从而切换到新进程。

volatile和synchronized的区别

好久不见. 提交于 2020-01-23 20:10:40
volatile和synchronized的区别 volatile本质是在告诉jvm当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取; synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。 volatile仅能使用在变量级别;synchronized则可以使用在变量、方法、和类级别的。 volatile仅能实现变量的修改可见性,不能保证原子性;而synchronized则可以保证变量的修改可见性和原子性。 volatile不会造成线程的阻塞;synchronized可能会造成线程的阻塞。 有可能有些读者还是会不大理解这里的区别,那我现在再来讲一讲线程安全的两个方面: 执行控制 和 内存可见 。 执行控制的目的是控制代码执行顺序及是否可以并发执行。 内存可见控制的是线程执行结果在内存中对其它线程的可见性。(根据Java内存模型的实现,线程在具体执行时,会先拷贝主存数据到线程本地(CPU缓存),操作完成后再把结果从线程本地刷到主存。) synchronized关键字解决的就是执行控制,它能控制代码执行的顺序,即如果一个线程正在进行被synchronized修饰的代码块时,它会阻止其他的线程进行这段代码块。更重要的是,synchronized还会创建一个内存屏障,内存屏障指令保证了所有CPU操作结果都会直接刷到主存中

volatile

∥☆過路亽.° 提交于 2020-01-23 13:12:36
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 { public static int count = 0; public static void inc() { //这里延迟1毫秒,使得结果明显 try { Thread

JDK源码那些事儿之浅析Thread上篇

ⅰ亾dé卋堺 提交于 2020-01-23 03:53:39
JAVA中多线程的操作对于初学者而言是比较难理解的,其实联想到底层操作系统时我们可能会稍微明白些,对于程序而言最终都是硬件上运行二进制指令,然而,这些又太过底层,今天来看一下JAVA中的线程,浅析JDK源码中的Thread类,之后能帮助我们更好的处理线程问题 前言 JDK版本号:1.8.0_171 在Thread注释中可以看到大佬对其进行的解释: Thread就是程序中一个线程的执行.JVM允许一个应用中多个线程并发执行 每个线程都有优先级.高优先级线程优先于低优先级线程执行 每个线程都可以(不可以)被标记为守护线程 当线程中的run()方法代码里面又创建了一个新的线程对象时,新创建的线程优先级和父线程优先级一样 当且仅当父线程为守护线程时,新创建的线程才会是守护线程 当JVM启动时,通常会有唯一的一个非守护线程(这一线程用于调用指定类的main()方法) JVM会持续执行线程直到下面某一个情况发生为止: 1.类运行时exit()方法被调用且安全机制允许此exit()方法的调用. 2.所有非守护类型的线程均已经终止,或者run()方法调用返回或者在run()方法外部抛出了一些可传播性的异常. 可以联想下JVM的启动过程,从main方法启动,可以自己写代码查看下线程情况 线程实现 Thread注释类上清楚的写明了线程的两种实现方式: 定义一个继承Thread类的子类

深入理解JVM

我与影子孤独终老i 提交于 2020-01-23 01:56:55
虚拟机内存模型中定义的访问操作如下图所示: java中通过多线程机制使得多个任务同时执行处理,所有的线程共享JVM内存区域 主存(Main memory),而每个线程都有自己独立的工作内存,当线程与内存区域进行交互时,数据从主存拷贝到工作内存,进而由线程处理(操作码+操作数)。 JVM逻辑内存模型如下: 接下来介绍每个的用途 : 1.程序计数器   当前线程所执行的字节码的行号指示器。通过改变计数器的值选取下一条指令。   分之,循环,跳转,异常处理,线程回复都依赖程序计数器完成。   多线程轮流切换分配处理器执行时间,在一个确定的时间,一个处理器(多核处理器的一个内核)只会执行一个线程的一条指令。   为了线程切换后能够恢复到正常的位置,每个线程都有独立的程序计数器,各条线程计数器互不影响,独立存储,我们称这类内存区域为“线程私有”的内存。   Java虚拟机规范:此内存区域是唯一一个没有规定任何OutofMemory情况的区域。 2.Java栈   与程序计数器一样,Java虚拟机栈(Java Vitual Machine Stacks)也是线程私有的,生命周期与线程相同。   该虚拟机栈描述的是Java方法执行的内存模型:每个方法执行的时候都会创建一个栈针(Stack Frame)用于存储局部变量表,操作栈,动态链接,方法出口等信息。   每一个方法被调用至执行完成的过程

Java面试 4.10 多线程

不想你离开。 提交于 2020-01-22 22:25:24
4.10.1 什么是线程?它与进程有什么区别?为什么要使用多线程 线程是指程序在执行过程中,能够执行程序代码的一个执行单元。 进程是指一段正在执行的程序。而线程有时也被称为轻量级进程,它是程序执行的最小单元,一个进程可以拥有多个线程,各个线程之间共享程序的内存空间(代码段、数据段和堆空间)及一些进程级的资源(例如打开的文件),但是各个线程拥有自己的栈空间。 在操作系统级别上,程序的执行都是以进程为单位的,而每个进程中通常都会有多个线程互不影响地并发执行,那么为什么要使用多线程呢?其实,多线程的使用为程序研发带来了巨大的便利,具体而言,有以下几个方面的内容: 1)使用多线程可以减少程序的响应时间。在单线程(单线程指的是程序执行过程中只有一个有效操作的序列,不同操作之间都有明确的执行先后顺序)的情况下,如果某个操作很耗时,或者陷入长时间的等待(如等待网络响应),此时程序将不会响应鼠标和键盘等操作,使用多线程后,可以把这个耗时的线程分配到一个单独的线程去执行,从而使程序具备了更好的交互性。 2)与进程相比,线程的创建和切换开销更小。由于启动一个新的线程必须给这个线程分配独立的地址空间,建立许多数据结构来维护线程代码段、数据段等信息,而运行于同一进程内的线程共享代码段、数据段,线程的启动或切换的开销比进程要少很多。同时多线程在数据共享方面效率非常高。 3)多 CPU

JVM运行机制

孤街醉人 提交于 2020-01-22 20:57:10
jvm启动流程 JVM基本结构 JVM内存空间: 1、方法区:    保存装载的类信息 类型常量池   字段、方法信息 方法字节码   通常和永久区(perm) 关联在一起 JDK6时,String等常量信息置于方法 JDK7时,已经移动到了堆 2、PC寄存器 每个线程拥有一个PC寄存器 在线程创建时创建 指向下一条指令的地址 执行本地方法时,PC的值为undefined 3、JAVA堆   和程序开发密切相关 应用系统对象都保存在Java堆中 所有线程共享Java堆 对分代GC来说,堆也是分代的 GC的主要工作区间 4、Java栈 线程私有 栈由一系列帧组成(因此Java栈也叫做帧栈) 帧保存一个方法的局部变量、操作数栈、常量池指针 每一次方法调用创建一个帧,并压栈    JAVA 栈之局部变量表: 包含局部变量 和参数,如下代码在栈帧中的结构: public class StackDemo { public static int runStatic(int i,long l,float f,Object o ,byte b){ return 0; } public int runInstance(char c,short s,boolean b){ return 0; } }   runStatic            runInstance java栈之操作数栈: