Month: March 2013

例示CyclicBarrier的使用

package player.kent.chen.learn.barrier; import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.CyclicBarrier; public class HelloBarrier { /** * 大家都到齐后,再一起开火 */ private static final class FireTogether implements Runnable { private CyclicBarrier barrier; public FireTogether(CyclicBarrier barrier) { super(); this.barrier = barrier; } public void run() { try { barrier.await(); //等别的线程到达集合点 System.out.println(Thread.currentThread().getName() + ": 哥开火了!"); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } catch (BrokenBarrierException …

例示CyclicBarrier的使用 Read More »

理解Java Interruption机制

本文内容基本源自 Java theory and practice: Dealing with InterruptedException Interruption机制是干什么用的? Interruption用于一个线程“礼貌地”打断另一个线程,被打断的线程可以理会,也可以不理会。(interruption is a way of politely asking another thread to stop what it is doing if it wants to, at its convenience. ) 不过后面可以看到,不理会者,不是好人(a good citizen) 具体怎么interrupt ? 1. 打断者执行thread.interrupt() 2. 被打断者要么收到InterruptedException, 要么会发现自己的isInterrupted() == true. 注意:    1. 如果被打断者在interruption来临时正在执行sleep(), I/O读写等Blocking Method, 则会收到InterruptedException(所以这些方法一般会throws InterruptedException)    2. 如果被打断者没有执行上述Blocking …

理解Java Interruption机制 Read More »

Java Semaphore例子

package player.kent.chen.learn.semaphore; import java.util.concurrent.Semaphore; public class HelloSemaphore { private static final class Room { //信号量作为共享资源的属性 private Semaphore semaPhore = new Semaphore(3, true); //每次只允许3个人在房内 public void take() throws InterruptedException { try { semaPhore.acquire(); System.out.println(Thread.currentThread().getName() + " is now in the room"); Thread.sleep(3000); } finally { semaPhore.release(); } } } private static final class Guest implements Runnable …

Java Semaphore例子 Read More »

CAS操作中的ABA问题及Java中的解决办法

一般的CAS在决定是否要修改某个变量时,会判断一下当前值跟旧值是否相等。如果相等,则认为变量未被其他线程修改,可以改。 但是,“相等”并不真的意味着“未被修改”。 另一个线程可能会把变量的值从A改成B,又从B改回成A。 这就是ABA问题。 很多情况下,ABA问题不会影响你的业务逻辑因此可以忽略。但有时不能忽略,这时要解决这个问题,一般的做法是给变量关联一个只能递增、不能递减的版本号。在compare时不但compare变量值,还要再compare一下版本号。 Java里的AtomicStampedReference 类就是干这个的。

JMM: 断点调试可能使不可见的变量变成可见

如果一个变量没有使用volatile标识,则可能存在跨线程可见性问题; 但经验发现,断点调试时,这个可见性问题可能会消失。 比如, package player.kent.chen.learn.hivolatile; /** * 循环直到有人喊停 */ public class LoopUntilCommandForBoolBean { private BoolBean bean = new BoolBean(false); /** * 循环直到有人喊停 */ public void loop() { System.out.println("loop starts"); while (!bean.isStop()) { ; } System.out.println("Stopped because somebody said so"); } /** * 喊停 */ public void sayStop() { bean.setStop(true); System.out.println("Stop said"); } public static void main(String[] …

JMM: 断点调试可能使不可见的变量变成可见 Read More »

例示:volatile是否只适用于primitve type ?

volatile是否只适用于primitve type? 也就是说,java对象是否也存在 主内存+工作内存副本这样的机制? 结论是:volatile对object reference也适用。 具体来说, 如果一个变量原来是指向对象A的,一个线程把它指向对象B后,另一个线程并不能感知这种变化。 例如, package player.kent.chen.learn.hivolatile; /** * 循环直到有人喊停 */ public class LoopUntilCommandForString { private static final String YES = "yes"; private static final String NO = "no"; private String stop = NO; /** * 循环直到有人喊停 */ public void loop() { System.out.println("Loop started"); while (stop == NO) { ; } …

例示:volatile是否只适用于primitve type ? Read More »

volatile的例子

package player.kent.chen.learn.hivolatile; /** * 循环直到有人喊停 */ public class LoopUntilCommand { private boolean stop; /** * 循环直到有人喊停 */ public void loop() { while (!stop) { ; } System.out.println("Stopped because somebody said so"); } /** * 喊停 */ public void sayStop() { stop = true; } public static void main(String[] args) throws InterruptedException { final LoopUntilCommand luc …

volatile的例子 Read More »

JVM指令重排的例子

package player.kent.chen.learn.reorder; import java.text.MessageFormat; //转账类 public class Transfer { private int amountA = 100; private int amountB = 100; private volatile boolean committed; //转账动作 public void doTransfer() { amountA = amountA – 50; amountB = amountB + 50; committed = true; } //转账结束时打印两个账户的值 public void printAccountsWhenDone() { if(!committed) { //转账未结束则等待。 return; } System.out.println(MessageFormat.format(“amountA = {0}, …

JVM指令重排的例子 Read More »

寄存器对JVM指令来说是不可见的

JVM的指令集不会直接使用寄存器作为操作数,也就是说JVM指令看不到寄存器。 java中的volatile也跟寄存器无关,每个线程保留的变量副本不是在寄存器里,而是在JMM定义的“工作内存”里。这个内存并非寄存器。 当然JVM在运行时可以把某些内存映射到寄存器,寄存器的存取速度比内存要快得多,所以这样可以提高一点性能。 但不管怎么样,这只是运行时的优化,就JVM指令模型本身而言,它是看不到寄存器的。

volatile不会被直接编译成特殊的jvm指令

volatile不会被直接编译成特殊的jvm指令; 相反,它只是存在于bytecode中作为变量的属性。到运行时,JVM才根据这个属性来决定如何生成对应的汇编指令。比如说,看到这个属性就禁止指令重排