volatile

JAVA多线程之先行发生原则

最后都变了- 提交于 2020-02-28 07:37:45
一、引子     如果java内存模型中所有的有序性都仅仅依靠volatile和synchronized来完成,那么有一些操作会变得很繁琐,但我们在编写java并发代码时并未感觉到这一点,这是因为java语言中有个先行发生原则(happens-before),通过这个原则,我们可以通过几条规则一揽子解决并发环境下两个操作之间是否可能存在冲突的所有问题。 二、定义   先行发生是java内存模型中定义的两项做错之间的偏序关系,如果说操作A先行发生与操作B,其实就是说在发生操作B之前,操作A产生的影响能被操作B观察到,“影响”包括修改了内存中共享变量的值、发送了消息、调用了方法等。 三、规则   java内存模型中“天然的”的先行发生关系规则如下:   1、程序次序规则:     在一个线程内,按照程序代码顺序,,书写在前面的操作先行发生于书写在后面的操作,准确的说,应该是控制流程序而不是程序代码顺序,因为要考虑分支、循环等结构;   2、管程锁规则:     一个unlock操作先行发生于后面对同一个锁的lock操作,这里必须强调的是同一个锁,“后面”指的是时间上的先后顺序。   3、volatile变量规则:     对一个volatile变量的写操作先行发生于后面对这个变量的读操作,“后面”同样是时间上的先后顺序。   4、线程启动规则:     Thread对象的start(

volatile关键字的原理与使用

不羁的心 提交于 2020-02-28 05:36:38
二、并发编程的3个基本概念 (1)原子性 定义: 即一个操作或者多个操作 要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行。 (2)可见性 定义:指当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值。 (3)有序性 定义:即程序执行的顺序按照代码的先后顺序执行。 二、volatile变量的特性 (1)保证可见性,不保证原子性 a.当写一个volatile变量时,JMM会把该线程本地内存中的变量强制刷新到主内存中去; b.这个写会操作会导致其他线程中的缓存无效。 (2)禁止指令重排 重排序是指编译器和处理器为了优化程序性能而对指令序列进行排序的一种手段。重排序需要遵守一定规则: a.重排序操作不会对***存在数据依赖关系***的操作进行重排序。 比如:a=1;b=a; 这个指令序列,由于第二个操作依赖于第一个操作,所以在编译时和处理器运 行时这两个操作不会被重排序。 b.重排序是为了优化性能,但是不管怎么重排序,单线程下程序的执行结果不能被改变 比如:a=1;b=2;c=a+b这三个操作,第一步(a=1)和第二步(b=2)由于不存在数据依赖关系, 所以可能会发 生重排序,但是c=a+b这个操作是不会被重排序的,因为需要保证最终的结果一定是c=a+b=3。 三、volatile原理: volatile可以保证线程可见性且提供了一定的有序性

java并发面试题(七)

白昼怎懂夜的黑 提交于 2020-02-28 03:29:19
重写run()方法时可以对外抛出异常么? 答:不行,因为被重写的run()方法自身就没有抛出异常的定义,所以run()方法里要是有异常,在内部就要try/catch了。 线程可以连续调用两次start方法么? 答:可参考本篇博客 线程连续两次调用start()方法 。 简述锁的等级方法锁、对象锁、类锁? 答:首先要了解每个对象都有一个可以用来实现同步的锁,称为内置锁。方法锁和对象锁指的其实是同一个东西,只是synchronized关键字使用的地方不同而已,都是作用于实例对象,所以如果是相同类的不同实例,它们的锁也是不同的。而类也是一个特殊的对象,类锁就是作用于类上的锁,比如静态同步方法的锁就是类锁,这时候再多的实例,只要它们归属的类是相同的,那抢的就是同一把锁。 多线程的价值? 答:首先可以充分利用多核CPU的优势,其次可以防止阻塞,完全可以在一个任务阻塞时,先做其他的任务,然后等第一个任务返回后再做统合,最后使用多线程可以对任务进行拆解,把一个大任务拆分成几个小任务运行,当然,能否成功拆解还是要看具体的业务逻辑。 锁机制有什么用? 答:多线程情况下,保证信息的同步,结果的正确。 请说出你所知的线程同步的方法? 答: wait() : 使一个线程处于等待状态,并且释放所持有的对象的锁。 sleep() : 使一个正在运行的线程处于睡眠状态(睡眠可以理解成睡到一定时间线程自己就会醒)

Java面试题-Java中的锁

杀马特。学长 韩版系。学妹 提交于 2020-02-28 00:18:45
1. 如何实现乐观锁(CAS)?如何避免ABA问题? 答:1)读取内存值的方式实现了乐观锁(比如:SVN系统),方法:第一,比较内存值和期望值;第二,替换内存值为要替换值。 2)带参数版本来避免aba问题,在读取和替换的时候进行判定版本是否一致 2. 读写锁可以用于什么应用场景? 答: 读写锁可以用于 “多读少写” 的场景,读写锁支持多个读操作并发执行,写操作只能由一个线程来操作 ReadWriteLock对向数据结构相对不频繁地写入,但是有多个任务要经常读取这个数据结构的这类情况进行了优化。ReadWriteLock使得你可以同事有多个读取者,只要它们都不试图写入即可。如果写锁已经被其他任务持有,那么任何读取者都不能访问,直至这个写锁被释放为止。 ReadWriteLock 对程序心性能的提高受制于如下几个因素也还有其他等等的因素。 1)数据被读取的频率与被修改的频率相比较的结果。 2)读取和写入的时间 3)有多少线程竞争 4)是否在多处理机器上运行 3. 什么时候应该使用可重入锁? 答:重入锁指的是在某一个线程中可以多次获得同一把锁,在线程中多次操作有锁的方法。 4. 什么场景下可以使用volatile替换synchronized? 答: 只需要保证共享资源的可见性的时候可以使用volatile替代,synchronized保证可操作的原子性一致性和可见性

Java并发高频面试题

雨燕双飞 提交于 2020-02-27 21:24:15
前面整理了Java基础、Mysql、Spring的高频面试题,今天为大家带来Java并发方面的高频面试题,因为并发知识不管在学习、面试还是工作过程中都非常非常重要,看完本文,相信绝对能助你一臂之力。 1、线程和进程有什么区别? 线程是进程的子集,一个进程可以有很多线程。每个进程都有自己的内存空间,可执行代码和唯一进程标识符(PID)。 每条线程并行执行不同的任务。不同的进程使用不同的内存空间(线程自己的堆栈),而所有的线程共享一片相同的内存空间(进程主内存)。别把它和栈内存搞混,每个线程都拥有单独的栈内存用来存储本地数据。 2、实现多线程的方式有哪些? 继承Thread类:Java单继承,不推荐; 实现Runnable接口:Thread类也是继承Runnable接口,推荐; 实现Callable接口:实现Callable接口,配合FutureTask使用,有返回值; 使用线程池:复用,节约资源; 更多方式可以参考我的文章使用Java Executor框架实现多线程 3、用Runnable还是Thread? 这个问题是上题的后续,大家都知道我们可以通过继承Thread类或者调用Runnable接口来实现线程,问题是,那个方法更好呢?什么情况下使用它?这个问题很容易回答,如果你知道Java不支持类的多重继承,但允许你调用多个接口。所以如果你要继承其他类

Is `*(volatile T*)0x1234;` guaranteed to translate into read instruction?

强颜欢笑 提交于 2020-02-27 19:31:10
问题 When working with hardware it is sometimes required to perform a read from a specific register discarding the actual value (to clear some flags, for example). One way would be to explicitly read and discard the value such as: int temp = *(volatile int*)0x1234; // 0x1234 is the register address (void)temp; // To silence the "unused" warning Another way that seem to work is simply: *(volatile int*)0x1234; But this doesn't seem to obviously imply the read access, yet it seems to translate to one

AtomicReference与volatile的区别

穿精又带淫゛_ 提交于 2020-02-27 08:53:29
首先volatile是java中关键字用于修饰变量,AtomicReference是并发包java.util.concurrent.atomic下的类。 首先volatile作用,当一个变量被定义为volatile之后,看做“程度较轻的 synchronized”,具备两个特性: 1.保证此变量对所有线程的可见性(当一条线程修改这个变量值时,新值其他线程立即得知) 2.禁止指令重新排序 注意volatile修饰变量不能保证在并发条件下是线程安全的,因为java里面的运算并非原子操作。 volatile说明 java.util.concurrent.atomic工具包,支持在单个变量上解除锁的线程安全编程。其基本的特性就是在多线程环境下,当有多个线程同时执行这些类的实例包含的方法时,具有排他性,即当某个线程进入方法,执行其中的指令时,不会被其他线程打断,而别的线程就像自旋锁一样,一直等到该方法执行完成,才由JVM从等待队列中选择一个另一个线程进入,这只是一种逻辑上的理解。 AtomicReference说明 Java 理论与实践: 正确使用 Volatile 变量 Java 语言中的 volatile 变量可以被看作是一种 “程度较轻的 synchronized ”;与 synchronized 块相比,volatile 变量所需的编码较少,并且运行时开销也较少

JAVA多线程

半世苍凉 提交于 2020-02-27 08:50:52
JAVA多线程 1.进程与线程介绍  进程:每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销,一个进程包含1--n个线程。(进程是资源分配的最小单位)。  线程:同一类线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器(PC),线程切换开销小。(线程是cpu调度的最小单位)。  进程的栈内存和堆内存都是独立的,而线程的栈内存是独立的,堆内存是共享的。 2.实现多线程的两种方式 继承Thread类,重写该类的run()方法。 实现Runnable接口,并重写该接口的run()方法,该run()方法同样是线程执行体,创建Runnable实现类的实例,并以此实例作为Thread类的target来创建Thread对象,该Thread对象才是真正的线程对象。 区别: 实现Runnable接口比继承Thread类所具有的优势: 1):适合多个相同的程序代码的线程去处理同一个资源 2):可以避免java中的单继承的限制 3):增加程序的健壮性,代码可以被多个线程共享,代码和数据独立 4):线程池只能放入实现Runable或callable类线程,不能直接放入继承Thread的类 3.线程池   Jdk1.5后提供了Executor为我们管理Thread对象,从而简化了并发编程。Executor允许你管理异步任务的执行,而无须显式地管理线程的生命周期且这是jdk1

Java多线程整理

空扰寡人 提交于 2020-02-27 08:50:24
目录: 1.volatile变量 2.Java并发编程学习 3. CountDownLatch用法 4. CyclicBarrier使用 5.BlockingQueue使用 6.任务执行器Executor 7.CompletionService使用 8.ConcurrentHashMap使用 9.Lock使用 一、 volatile变量   1.volatile原理:volatile的原理实际上是告诉处理器,不要把变量缓存在寄存器或者相对于其他处理器不可见的地方,而是把变量放在主存,每次读写操作都在主存上进行操作。另外,被申明为volatile的变量也不会与其它内存中的变量进行重排序。   2.volatile同步:volatile是同步的一个子集,只保证了变量的可见性,但是不具备原子特性。这就是说线程能够自动发现 volatile 变量的最新值。相对于同步而言,volatile的优势:a.简易性,可以像使用其他变量一样使用volatile变量;b.volatile变量不会造成线程阻塞;c.如果读操作远远大于写操作,volatile 变量还可以提供优于锁的性能优势。   3.正确使用volatile条件:对变量的写操作不依赖于当前值;该变量没有包含在具有其他变量的不变式中; /* * 对于第一条原则:对变量的写操作不依赖于当前值; * 虽然i++只有一条语句

Volatile关键字补充

こ雲淡風輕ζ 提交于 2020-02-27 08:29:21
前言 之前转载的文章 volatile关键字解析 中详细分析了volatile相关的知识(写的非常非常好!),这里就两点详细说下。 Synchonized保证可见性(以println方法为例) 之前有一次和朋友聊天说起System.out的各种print方法,当时他说这些方法内部除了IO外还有些别的逻辑,但当时没有特别在意。看了上面的博客后才意识到println通过同步的方法保证了可见性。用代码来解释吧: public class AtomicIntegerTest { static volatile AtomicInteger x = new AtomicInteger(0); //1 //static AtomicInteger x = new AtomicInteger(0); //2 public static void main(String[] args) { ExecutorService service = Executors.newCachedThreadPool(); service.execute(new TestThread1()); service.execute(new TestThread2()); service.shutdown(); } static class TestThread1 implements Runnable{ @Override