日志分类:并发

happens-before俗解

分类:java, 并发评论:13条作者:ticmy日期:2013-11-17

学习Java并发,到后面总会接触到happens-before偏序关系。初接触玩意儿简直就是不知所云,下面是经过一段时间折腾后个人对此的一点浅薄理解,希望对初接触的人有帮助。如有不正确之处,欢迎指正。 synchronized、大部分锁,众所周知的一个功能就是使多个线程互斥/串行的(共享锁允许多个线程同时访问,如读锁)访问临界区,但他们的第二个功能 —— 保证变量的可见性 —— 常被遗忘。 为什么存在可见性问题?简单介绍下。相对于内存,CPU的速度是极高的,如果CPU需要存取数据时都直接与内存打交道,在存取过程中,CPU将一直空闲,这是一种极大的浪费,妈妈说,浪费是不好的,所以,现代的CPU里都有很多寄存器,多级cache,他们比内存的存取速度高多了。某个线程执行时,内存中的一份数据,会存在于该线程的工作存储中(working memory,是cache和寄存器的一个抽象,这个解释源于《Concurrent Programming in Java: Design Principles and Patterns, Second Edition》§2.2.7,原文:Every thread is defined to have a working memory (an abstraction of caches and registers) in which to store values. 有不少人觉得working memory是内存的某个…

wait操作无故退出?

分类:java, 并发评论:5条作者:ticmy日期:2013-04-05

前不久在网上看到这样一个例子: class MyThread extends Thread { public void run() { System.out.println(getName() + "开始sleep"); try { Thread.sleep(2000); } catch (Exception e) { e.printStackTrace(); } System.out.println(getName() + "结束sleep"); } } public class TestWaitNotify { public static void main(String[] args) throws Exception { Thread myThread = new MyThread(); myThread.start(); synchronized (myThread) { myThread.wait(); } System.out.println("wait结束."); } } myThread执行结束后,main线程中的wait操作就自动退出了。程序里也并没有看到有notify/notifyAll调用。 如果将程序改成下面这样: class MyThread extends Thread { public void run() { System.out.println(getName() + "开始sleep"); try { Thread.sleep(2000); } catch (Exception e) { e.print…

ScheduledThreadPoolExecutor实现原理

分类:java, 并发评论:7条作者:ticmy日期:2013-01-09

自jdk1.5开始,Java开始提供ScheduledThreadPoolExecutor类来支持周期性任务的调度,在这之前,这些工作需要依靠Timer/TimerTask或者其它第三方工具来完成。但Timer有着不少缺陷,如Timer是单线程模式,调度多个周期性任务时,如果某个任务耗时较久就会影响其它任务的调度;如果某个任务出现异常而没有被catch则可能导致唯一的线程死掉而所有任务都不会再被调度。ScheduledThreadPoolExecutor解决了很多Timer存在的缺陷。 先来看看ScheduledThreadPoolExecutor的实现模型,它通过继承ThreadPoolExecutor来重用线程池的功能,里面做了几件事情: 为线程池设置了一个DelayedWorkQueue,该queue同时具有PriorityQueue(优先级大的元素会放到队首)和DelayQueue(如果队列里第一个元素的getDelay返回值大于0,则take调用会阻塞)的功能 将传入的任务封装成ScheduledFutureTask,这个类有两个特点,实现了java.lang.Comparable和java.util.concurrent.Delayed接口,也就是说里面有两个重要的方法:compareTo和getDelay。ScheduledFutureTask里面存储了该任务距离下次调度还需要的时间(使用的是基于System#nanoTime实现的相对时间,不…

[翻译]JSR 133 (Java Memory Model) FAQ

分类:java, 并发, 翻译评论:9条作者:ticmy日期:2012-12-11

JSR 133 (Java Memory Model) FAQ Jeremy Manson and Brian Goetz, February 2004 内容列表 究竟什么是内存模型? 其它语言,像C++,有内存模型吗? JSR133是什么? 重排序意味着什么? 老的内存模型有什么问题? 未正确同步是什么意思? 同步做了什么? final字段的值是如何看起来会变的? 在新的JMM下final字段是怎么工作的? volatile做了什么? 新的内存模型修复了“双重锁定检查”问题吗? 如果我要写一个VM呢? 为什么我要关心Java内存模型? 究竟什么是内存模型? 在多处理器系统中,处理器通常都有一到多级存储缓存,通过加速数据访问(因为数据距处理器更近)以及减少存储总线的流量(因为本地缓存可以满足某些存储操作)以提升性能。存储缓存能极大地提升性能,但也面临着大量新的难题。例如,当两个处理器同时检查相同的内存地址时会怎么样?在什么条件下它们将看到相同的值? 在处理器层面,针对其它处理器写入内存的值何时对当前处理器可见,以及当前处理器写入的值何时对其它处理器可见,内存模型为它们定义了充要条件。有些处理器表现出了强内存模型,对于任一给定的内存地址所有处理器看到的总是相同的值。另一些处理器则表现出…

hotspot中Thread#isInterrupted的并发可见性bug

分类:java, 并发评论:2条作者:ticmy日期:2012-11-14

这是在concurrency-interest邮件列表看到的一个hotspot bug。 在《The Java Language Specification Java SE 7 Edition》中17.4.4Synchronization Order小节中有这么一句描述: If thread T1 interrupts thread T2, the interrupt by T1 synchronizes-with any point where any other thread (including T2) determines that T2 has been interrupted(by having an InterruptedException thrown or by invoking Thread.interrupted or Thread.isInterrupted). 线程t1 interrupt了线程t2,那么线程t2调用Thread.isInterrupted就会返回true,然而在hotspot几个版本中却没有体现出来,测试代码如下: public class InterruptedVisibilityTest { public void think() { System.out.println("新线程正在执行"); while (true) { if (checkInterruptedStatus()) break; } System.out.println("新线程退出循环"); } private boolean checkInterruptedStatus() { return Thread.currentThread().isInterrupted(); } public stati…

ScheduledThreadPoolExecutor与System#nanoTime

分类:java, 并发评论:1条作者:ticmy日期:2012-11-13

一直流传着Timer使用的是绝对时间,ScheduledThreadPoolExecutor使用的是相对时间,那么ScheduledThreadPoolExecutor是如何实现相对时间的? 先看看ScheduledThreadPoolExecutor中实现定时调度的模型,很简单,内部用了无界的DelayQueue作为线程池的队列,而DelayQueue的内部又使用的是一个PriorityQueue,那么,最先需要定时调度的任务位于队首。定时任务实现逻辑大概如此:创建ScheduledThreadPoolExecutor对象的时候会记录一个常量值t,定时任务中有一个以t为基础的多久以后会被执行的属性,在线程拿到队首任务(可能等待了一段时间)执行后,会修改这个属性为下一次要执行的基于t的时间量,然后将其再放入队列中。整个逻辑都在任务的run方法中: public void run() { if (isPeriodic()) runPeriodic(); else ScheduledFutureTask.super.run(); } 如果是周期性任务,会执行runPeriodic: private void runPeriodic() { boolean ok = ScheduledFutureTask.super.runAndReset(); boolean down = isShutdown(); // Reschedule if not cancelled and not shutdown or policy allows if (ok && (!down…