一:AtomicInteger
publicclassContentType
{
publicstaticAtomicInteger ai=
newAtomicInteger(0);
publicstaticvoidmain(String[]
args) throwsInterruptedException {
finalCountDownLatch latch=
newCountDownLatch(1000);
for(inti = 0; i
< 1000; i++) {
Thread
thread = newThread() {
@Override
publicvoidrun()
{
ai.incrementAndGet();
System.out.println("-------"+
ai.get());
latch.countDown();
}
};
thread.setDaemon(true);
thread.start();
}
Thread
thread = newThread() {
@Override
publicvoidrun()
{
while(true)
{
ai.incrementAndGet();
System.out.println("---循環----"+ ai.get());
}
//
latch.countDown();
}
};
//
thread.setDaemon(true);
thread.start();
latch.await();
// while
(true) {
System.out.println("ai : "
+ ai.get());
//
Thread.sleep(100);
//
}
}
}
latch.await(); 使目前線程在鎖存器倒計數至零之前一直等待,除非線程被中斷。用來保證for循環執行結束以後列印結果。
AtomicInteger操作是原子性的
二:volatile
publicclassCounter
{
publicstaticintcount=
0;
publicstaticvoidinc()
{
// 這裡延遲1毫秒,使得結果明顯
try{
Thread.sleep(1);
}
catch(InterruptedException e) {
}
count++;
}
publicstaticvoidmain(String[]
args) throwsInterruptedException {
// 同時啟動1000個線程,去進行i++計算,看看實際結果
finalCountDownLatch
latch = newCountDownLatch(1000);
for(inti = 0; i
< 1000; i++) {
newThread(newRunnable()
{
@Override
publicvoidrun()
{
latch.countDown();
try{
latch.await();
}
catch(InterruptedException e) {
//
TODOAuto-generated catch block
e.printStackTrace();
}
Counter.inc();
}
}).start();
}
// 這裡每次運作的值都有可能不同,可能為1000
while(true)
{
System.out.println("運作結果:Counter.count="+
Counter.count);
Thread.sleep(100);
}
}
}
運作結果:Counter.count=992
運作結果還是沒有我們期望的1000,下面我們分析一下原因
在 java
垃圾回收整理一文中,描述了jvm運作時刻記憶體的配置設定。其中有一個記憶體區域是jvm虛拟機棧,每一個線程運作時都有一個線程棧,
線程棧儲存了線程運作時候變量值資訊。當線程通路某一個對象時候值的時候,首先通過對象的引用找到對應在堆記憶體的變量的值,然後把堆記憶體
變量的具體值load到線程本地記憶體中,建立一個變量副本,之後線程就不再和對象在堆記憶體變量值有任何關系,而是直接修改副本變量的值,
在修改完之後的某一個時刻(線程退出之前),自動把線程變量副本的值回寫到對象在堆中變量。這樣在堆中的對象的值就産生變化了。