日志标签:concurrency

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…

[翻译]Happens before偏序

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

原文:http://www.cs.umd.edu/class/fall2010/cmsc433/lectures/happens-before.txt “Happens before”是由Leslie Lamport引入的用来描述程序事件的一种偏序关系。 将多线程的执行看作是事件E的轨迹R,定义如下(轨迹只是一种次序): Events E ::= start(T) | end(T) | read(T,x,v) | write(T,x,v) | spawn(T1,T2) | join(T1,T2) | lock(T,x) | unlock(T,x) 这里T是一个线程标识符,x是一个变量,v是一个值。read(T,x,v)事件表示线程T从变量x中读出值v。同时假定轨迹R是结构良好的,即要求在R中,线程T的第一个事件必须是start(T)。在end(T)之后不再有线程T相关的事件。 设E1 < E2为E1和E2在轨迹中出现的顺序,它是可传递的、反自反的和反对称的。定义轨迹R中的happens-before次序(<:)如下: E1 <: E2,当且仅当E1 < E2,且下列条件之一成立: a) thread(E1) = thread(E2) b) E1为spawn(T1,T2), E2为start(T2) c) E2为join(T1,T2),E1为end(T2) d) E1为unlock(T1,x),E2为lock(T2,x) e) 存在这样的E3:E1 <: E3 且 E3 <: E2 (即…