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才根据这个属性来决定如何生成对应的汇编指令。比如说,看到这个属性就禁止指令重排

以填酒、喝酒为例说明线程同步:阻塞、死锁、非阻塞、Notify/Wait机制

一个填酒线程,一个喝酒线程对一个酒杯轮流进行操作。 阻塞、死锁 package player.kent.chen.learn.threads.notify; /** * 酒杯 * * @author kent 2013-3-11下午4:34:30 */ public class Cup { private volatile boolean empty = true; /** * 填酒,阻塞式地 * * @author kent 2013-3-11下午4:59:33 */ public synchronized void fill() { while (!empty) { //若酒杯不为空则等待 ; } doFill(); } /** * 清空酒杯,阻塞式地 * * @author kent 2013-3-11下午4:59:50 */ public …

以填酒、喝酒为例说明线程同步:阻塞、死锁、非阻塞、Notify/Wait机制 Read More »

代码示例:java.util.concurrent.locks.Lock

import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * @author kent 2013-3-11上午11:55:28 */ public class PlayLock implements Runnable { private Bean bean; public PlayLock(Bean bean) { super(); this.bean = bean; } public void run() { for (int j = 0; j < 100; j++) { bean.increment(); } } private static final class Bean { private int i = …

代码示例:java.util.concurrent.locks.Lock Read More »