状态变量

Volatile 说明

元气小坏坏 提交于 2020-01-04 02:51:08
Java™ 语言包含两种内在的同步机制:同步块(或方法)和 volatile 变量。这两种机制的提出都是为了实现代码线程的安全性。其中 Volatile 变量的同步性较差(但有时它更简单并且开销更低),而且其使用也更容易出错。 Java 语言中的 volatile 变量可以被看作是一种 “程度较轻的 synchronized ”;与 synchronized 块相比,volatile 变量所需的编码较少,并且运行时开销也较少,但是它所能实现的功能也仅是 synchronized 的一部分。本文介绍了几种有效使用 volatile 变量的模式,并强调了几种不适合使用 volatile 变量的情形。 锁提供了两种主要特性: 互斥(mutual exclusion) 和 可见性(visibility) 。互斥即一次只允许一个线程持有某个特定的锁,因此可使用该特性实现对共享数据的协调访问协议,这样,一次就只有一个线程能够使用该共享数据。可见性要更加复杂一些,它必须确保释放锁之前对共享数据做出的更改对于随后获得该锁的另一个线程是可见的 —— 如果没有同步机制提供的这种可见性保证,线程看到的共享变量可能是修改前的值或不一致的值,这将引发许多严重问题。 Volatile 变量 Volatile 变量具有 synchronized 的可见性特性,但是不具备原子特性。这就是说线程能够自动发现

线程同步,条件变量pthread_cond_wait

混江龙づ霸主 提交于 2020-01-01 00:24:11
与互斥锁不同,条件变量是用来等待而不是用来上锁的。条件变量用来自动阻塞一个线程,直到某特殊情况发生为止。条件变量使我们可以睡眠等待某种条件出现。 条件变量是利用线程间共享的全局变量进行同步的一种机制, 主要包括两个动作: 一个线程等待"条件变量的条件成立"而挂起;另一个线程使"条件成立"(给出条件成立信号)。 条件的检测是在互斥锁的保护下进行的。如果条件为假,一个线程自动阻塞,并释放等待状态改变的互斥锁。 pthread_cond_wait 原子调用: 等待条件变量, 解除锁, 然后阻塞 当 pthread_cond_wait 返回,则条件变量有信号,同时上锁 等待条件有两种方式: 条件等待pthread_cond_wait()和计时等待pthread_cond_timedwait(), 其中计时等待方式如果在给定时刻前条件没有满足,则返回ETIMEOUT 无论哪种等待方式,都必须和一个互斥锁配合,以防止多个线程同时请求pthread_cond_wait() (或pthread_cond_timedwait(),下同)的竞争条件(Race Condition)。 mutex互斥锁必须是普通锁(PTHREAD_MUTEX_TIMED_NP)或者适应锁(PTHREAD_MUTEX_ADAPTIVE_NP), 且在调用pthread_cond_wait()前必须由本线程加锁

java多线程与并发(基础篇)

孤街醉人 提交于 2019-12-24 19:06:31
一、进程与线程 进程 :是代码在数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位。 线程 :是进程的一个执行路径,一个进程中至少有一个线程,进程中的多个线程共享进程的 资源。 虽然系统是把资源分给进程,但是CPU很特殊,是被分配到线程的,所以线程是CPU分配的基本单位。 二者关系: 一个进程中有多个线程,多个线程共享进程的堆和方法区资源,但是每个线程有自己的程序计数器和栈区域。 程序计数器 :是一块内存区域,用来记录线程当前要执行的指令地址 。 栈 :用于存储该线程的局部变量,这些局部变量是该线程私有的,除此之外还用来存放线程的调用栈祯。 堆 :是一个进程中最大的一块内存,堆是被进程中的所有线程共享的。 方法区 :则用来存放 NM 加载的类、常量及静态变量等信息,也是线程共享的 。 二者区别: 进程 :有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响。 线程 :是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉。 1) 简而言之,一个程序至少有一个进程,一个进程至少有一个线程. 2) 线程的划分尺度小于进程,使得多线程程序的并发性高。 3) 另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。 4) 每个独立的线程有一个程序运行的入口

并发基础知识 — 线程安全性

删除回忆录丶 提交于 2019-12-23 18:55:54
前段时间看完了《并发编程的艺术》,总感觉自己对于并发缺少一些整体的认识。今天借助《Java并发编程实践》,从一些基本概念开始,重新整理一下自己学过并发编程。从并发基础开始,深入进去,系统学习一下并发编程。   编写线程安全的代码,核心在于要对状态访问操作进行管理,特别是对共享的(Shared)和可变的(Mutable)状态的访问。对象的状态是指存储在状态变量(实例或静态域)中的数据。对象的状态还可能包括其他依赖对象的域。(Map.Entry)   一个对象是否需要时线程安全的,取决于该对象是否被多线程访问。这指的是程序中访问对象的方式,而不是对象要实现的功能。要使得对象是线程安全的,要采用同步机制来协同对对象可变状态的访问。Java常用的同步机制是 Synchronized ,还包括 volatile 类型的变量,显示锁以及原子变量。   线程安全的程序是否完全由线程安全的类构成?答案是否定的,完全由线程安全的类构成的程序并不一定是线程安全的,线程安全类中也可以包含非线程安全的类。只有当类中仅包含自己的状态时,线程安全类才有意义! 什么是线程安全性?   当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些线程将如何交替执行,并且在主调代码中不需要任何额外的同步或协同,这个类都能表现出正确的行为,那么这个类就是线程安全的。   正确性:某个类的行为与其规范相一致。

线程的同步

左心房为你撑大大i 提交于 2019-12-22 05:10:36
多个线程共享相同的内存时,需要确保每个线程看到一致的数据视图。 1.互斥量 可以通过使用pthread的互斥接口保护数据,确保同一时间只有一个线程访问数据,互斥量(mutex)从本质上说是一把锁, 在访问共享资源前对互斥量进行加锁,在访问完成后释放互斥量上的锁。对互斥量进行加锁后,任何其他试图再次对互斥 量进行加锁的线程将被阻塞直到当前线程释放该互斥锁。如果释放互斥锁时有多个线程阻塞,所有在该互斥锁上阻塞线程都会变成可运行状态,第一个变为运行状态的线程可以对互斥量进行加锁,其他线程将会看到互斥锁依然被锁住,只有回去再次等待它重新变成可用。在这种方式下,每次只有一个线程可以向前执行。 互斥变量用pthread_mutex_t数据类型来表示,在使用互斥变量以前,必须首先对它进行初始化,可以把它置为常量PTHREAD_MUTEX_INITIALIZER(只对静态分配的互斥量),也可以通过调用pthread_mutex_init函数进行初始化。如果动态地分配互斥量(例如通过调用malloc),那么在释放内存前需要调用pthread_mutex_destroy。 #include<pthread.h> int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr

2020年Java面试100题

别来无恙 提交于 2019-12-19 01:54:10
一、Java 基础 1. JDK 和 JRE 有什么区别? JDK:Java Development Kit 的简称,java 开发工具包,提供了 java 的开发环境和运行环境。 JRE:Java Runtime Environment 的简称,java 运行环境,为 java 的运行提供了所需环境。 具体来说 JDK 其实包含了 JRE,同时还包含了编译 java 源码的编译器 javac,还包含了很多 java 程序调试和分析的工具。简单来说:如果你需要运行 java 程序,只需安装 JRE 就可以了,如果你需要编写 java 程序,需要安装 JDK。 2. == 和 equals 的区别是什么? == 解读 对于基本类型和引用类型 == 的作用效果是不同的,如下所示: 基本类型:比较的是值是否相同; 引用类型:比较的是引用是否相同; 代码示例: String x = "string"; String y = "string"; String z = new String("string"); System.out.println(x==y); // true System.out.println(x==z); // false System.out.println(x.equals(y)); // true System.out.println(x.equals(z));

026 UNIX再学习 -- 线程同步

六月ゝ 毕业季﹏ 提交于 2019-12-18 22:05:52
一、为什么要线程同步 当多个控制线程共享相同的内存时,需要确保每个线程看到一致的数据视图。如果每个线程使用的变量都是其他线程不会读取和修改的,那么就不存在一致性问题。同样,如果变量时只读的,每个线程同时读取该变量也不会有一致性问题。但是, 当一个线程可以修改的变量,其他线程也可以读取或者修改的时候,我们就需要对这些线程进行同步,确保它们在访问变量的存储内容时不会访问到无效的值 。 当一个线程修改变量时,其他线程在读取这个变量时可能会看到一个不一致的值。在变量修改时间多于一个存储器访问周期的处理器结构中,当存储器读与存储器写这两个周期交叉时,这种不一致就会出现。当然,这种行为是与处理器体系结构相关的,但是可移植的程序并不能对使用何种处理器体系结构做出任何假设。 上图中描述了两个线程读写相同变量的假设例子。在这个例子中,线程 A 读取变量然后给这个变量赋予一个新的数值,但写操作需要两个存储器周期。当线程 B 在这两个存储器写周期中间读取这个变量时,它就会得到不一致的值。 为了解决这个问题,线程不得不使用锁,同一时间只允许一个线程访问该变量。 如果线程 B 希望读取变量,它首先要获取锁。同样,当线程 A 更新变量时,也需要获取同样的这把锁。这样,线程 B 在线程 A 释放锁以前就不能读取变量。 总结一下, 多线程共享进程中的资源,多个线程同时访问相同的共享资源时,需要相互协调

关闭线程池的正确姿势,shutdown(), shutdownNow()和awaitTermination() 该怎么用?

走远了吗. 提交于 2019-12-17 04:27:15
ExecutorService 接口提供了三个方法用于手动关闭线程池,分别是 shutdown() , shutdownNow() 和 awaitTermination() 。我们最经常使用的 ThreadPoolExecutor 正是 ExecutorService 的实现类,自然也实现了这些方法。相信有很多小伙伴都没搞明白这些方法的区别,也不清楚在不同的情况下应该使用哪个方法。本文将通过 ThreadPoolExecutor 源码分析和简单用例向你展示这些方法的区别联系和使用场景,很多重点都在代码块的注释中,注意看哦!话不多说,上源码。 一、源码分析 1.1 线程池运行状态 ThreadPoolExecutor 使用 runState (运行状态)这个变量对线程池的生命周期进行控制,线程池关闭过程会有频繁的运行状态转化,所以我们首先需要了解线程池的各种运行状态及其之间的转化关系, runState 一共有以下5种取值: RUNNING:接收新的任务并对任务队列里的任务进行处理; SHUTDOWN:不再接收新的任务,但是会对任务队列中的任务进行处理; STOP:不接收新任务,也不再对任务队列中的任务进行处理,并中断正在处理的任务; TIDYING:所有任务都已终止,线程数为0,在转向 TIDYING 状态的过程中,线程会执行 terminated() 钩子方法

线程常用25道题

谁都会走 提交于 2019-12-16 15:04:35
并发编程三要素? 1)原子性 原子性指的是一个或者多个操作,要么全部执行并且在执行的过程中不被其他操作打断,要么就全部都不执行。 2)可见性 可见性指多个线程操作一个共享变量时,其中一个线程对变量进行修改后,其他线程可以立即看到修改的结果。 3)有序性 有序性,即程序的执行顺序按照代码的先后顺序来执行。 Thread.sleep(0)的作用是什么? 由于Java采用抢占式的线程调度算法,因此可能会出现某条线程常常获取到CPU控制权的情况,为了让某些优先级比较低的线程也能获取到CPU控制权,可以使用Thread.sleep(0)手动触发一次操作系统分配时间片的操作,这也是平衡CPU控制权的一种操作。 java中的++操作符线程安全么?? 不是线程安全的操作。它涉及到多个指令,如读取变量值,增加,然后存储回内存,这个过程可能会出现多个线程交差 Runnable和Callable有什么区别? Callable规定(重写)的方法是call(),Runnable规定(重写)的方法是run()。 Callable的任务执行后可返回值,而Runnable的任务是不能返回值的。 Call方法可以抛出异常,run方法不可以。 运行Callable任务可以拿到一个Future对象,表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并检索计算的结果

手把手,嘴对嘴,讲解UCOSII嵌入式操作系统的任务调度策略(四)

假装没事ソ 提交于 2019-12-16 15:04:12
继续...... 再回到那个重要得函数: void OS_Sched (void) { #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ OS_CPU_SR cpu_sr = 0u; #endif OS_ENTER_CRITICAL(); if (OSIntNesting == 0u) { /* Schedule only if all ISRs done and ... */ if (OSLockNesting == 0u) { /* ... scheduler is not locked */ OS_SchedNew(); OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy]; if (OSPrioHighRdy != OSPrioCur) { /* No Ctx Sw if current task is highest rdy */ #if OS_TASK_PROFILE_EN > 0u OSTCBHighRdy->OSTCBCtxSwCtr++; /* Inc. # of context switches to this task */ #endif OSCtxSwCtr++; /* Increment context switch