作者归档
可见性问题实例
说到并发安全时,我们常提及可见性的问题,通俗点讲就是线程1看不到线程2写入变量v的值(更专业的解释以及是什么导致可见性问题,又该如何解决,见扩展阅读),但一直偏于理论,实际中有没有因可见性而导致问题的例子呢?回答是肯定的,接下来我们一起来看几个例子。
这个例子很简单,新建的线程里有一个普通变量stop,用来表示是否结束循环里的自增操作。主线程启动这个线程后,将该变量置为true,观察线程是否打印出finish loop那行,如果存在可见性问题,主线程修改stop值为true,线程v看stop的值应该还是false。
[code lang=”java”]
class VisibilityThread extends Thread {
private boolean stop;
public void run() {
int i = 0;
System.out.println("start loop.");
while(!getStop()) {
i++;
}
System.out.println("finish loop,i=" + i);
}
public void stopIt() {
stop = true;
}
public boolean getStop(){
return stop;
}
}
public class VisibilityTest {
public static void main(String[] args) throws Exception {
VisibilityThread v = new VisibilityThread();
v.start();
Thread.sleep(1000);//停顿1秒等待新启线程执行
System.out.println("即将置stop值为true");
v.stopIt();
Thread.sleep(1000);
System.out.println("finish main");
System.out.println("main中通过getStop获取的stop值:" + v.getStop());
}
}
[/code]
竞态条件与临界区
原文链接 作者:Jakob Jenkov 译者:He Jianjun 校对:丁一
在同一程序中运行多个线程本身不会导致问题,问题在于多个线程访问了相同的资源。如,同一内存区(变量,数组,或对象)、系统(数据库,web services等)或文件。实际上,这些问题只有在一或多个线程向这些资源做了写操作时才有可能发生,只要资源没有发生变化,多个线程读取相同的资源就是安全的。
并发译文翻译计划(三)
为了促进并发编程在中国的推广和研究,让更多的同学能阅读到国外的文献。所以打算将国外的编程文献翻译成中文,但是我一个人的精力有限,所以希望征集译者帮忙一起翻译。这是一篇比较基础的文章,希望翻译后对新手有很大帮助。
- Introduction to Java Concurrency(译者:jiyou)
- Benefits (译者:古圣昌)
- Costs (译者:古圣昌)
- Creating and Starting Threads(译者:阿里-章筱虎)
- Race Conditions and Critical Sections(译者:He Jianjun,已完成)
- Thread Safety and Shared Resources(译者:Bi Ran,已完成)
- Thread Safety and Immutability(译者:高嵩,已完成)
- Synchronized Blocks (译者:同杰)
- Thread Signaling (译者:杜建雄)
- Deadlock (译者:申章)
- Deadlock Prevention (译者:申章)
- Starvation and Fairness (译者: jiyou)
- Nested Monitor Lockout(译者:柳暗 ☆花明)
- Slipped Conditions(译者:柳暗 ☆花明)
- Locks (译者:申章)
- Read / Write Locks(译者:华)
- Reentrance Lockout(译者:刘晓日)
- Semaphores (译者:寒桐)
- Blocking Queues (译者:寒桐)
- Thread Pools (译者:长源)
- Anatomy of a Synchronizer(译者:高嵩)
有兴趣的同学可以一起参与。 阅读全文
伪共享(False Sharing)
原文地址:http://ifeve.com/false-sharing/
作者:Martin Thompson 译者:丁一
缓存系统中是以缓存行(cache line)为单位存储的。缓存行是2的整数幂个连续字节,一般为32-256个字节。最常见的缓存行大小是64个字节。当多线程修改互相独立的变量时,如果这些变量共享同一个缓存行,就会无意中影响彼此的性能,这就是伪共享。缓存行上的写竞争是运行在SMP系统中并行线程实现可伸缩性最重要的限制因素。有人将伪共享描述成无声的性能杀手,因为从代码中很难看清楚是否会出现伪共享。
为了让可伸缩性与线程数呈线性关系,就必须确保不会有两个线程往同一个变量或缓存行中写。两个线程写同一个变量可以在代码中发现。为了确定互相独立的变量是否共享了同一个缓存行,就需要了解内存布局,或找个工具告诉我们。Intel VTune就是这样一个分析工具。本文中我将解释Java对象的内存布局以及我们该如何填充缓存行以避免伪共享。
阅读全文
任务取消(Cancellation)
原文链接:http://gee.cs.oswego.edu/dl/cpj/cancel.html
作者:Doug Lea 译者:丁一
当某个线程中的活动执行失败或想改变运行意图,也许就有必要或想要在其它线程中取消这个线程的活动,而不管这个线程正在做什么。取消会给运行中的线程带来一些无法预料的失败情况。取消操作异步特性相关的设计技巧,让人想起了因系统崩溃和连接断开任何时候都有可能失败的分布式系统的那些技巧。并发程序还要确保多线程共享的对象的状态一致性。
在大多数多线程程序中,取消任务(Cancellation)是普遍存在的,常见于:
- 几乎所有与GUI中取消按钮相关的活动。
- 多媒体演示(如动画循环)中的正常终止活动。
- 线程中生成的结果不再需要。例如使用多个线程搜索数据库,只要某个线程返回了结果,其它的都可以取消掉。
- 由于一组活动中的一或多个遇到意外错误或异常导致整组活动无法继续。
脚注:在并发编程中两个l的cancellation最常见。译者注:英语”取消”有两种写法cancelation和cancellation
Java内存模型Cookbook(四)指南(Recipes)
原文:http://gee.cs.oswego.edu/dl/jmm/cookbook.html
作者:Doug Lea 翻译:丁一
单处理器(Uniprocessors)
如果能保证正在生成的代码只会运行在单个处理器上,那就可以跳过本节的其余部分。因为单处理器保持着明显的顺序一致性,除非对象内存以某种方式与可异步访问的IO内存共享,否则永远都不需要插入屏障指令。采用了特殊映射的java.nio buffers可能会出现这种情况,但也许只会影响内部的JVM支持代码,而不会影响Java代码。而且,可以想象,如果上下文切换时不要求充分的同步,那就需要使用一些特殊的屏障了。
Happens before
原文: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相关的事件。
阅读全文