背景
? ? ? ? 最近在看《深入理解Java虛擬機:JVM高級特性與最佳實踐(第3版) 周志明》這本書,書中有些代碼示例是為了讓讀者理解作者表達(dá)的意思,但不是完整的代碼示例,所以針對這些不完整的代碼,自己動手寫出完整的代碼示例。
說明
(1)在看這本書的同學(xué),可以拿我這里的示例代碼做個參考,并歡迎提出意見和建議;
(2)示例的標(biāo)號,是和書中的代碼示例標(biāo)號相對應(yīng)的。文章來源:http://www.zghlxwxcb.cn/news/detail-815474.html
第12章 -?代碼
示例:12-1
/**
* 這個程序演示的是:《深入理解JVM》(周志明 第三版) 代碼清黨12-1 volatile運算
*
* volatile關(guān)鍵字只能保證可見性,并不能保證原子性(和有序性)
* 因為程序輸出的結(jié)果有不等于200000的情況發(fā)生
*/
public class VolatileTest_12_1 {
public static volatile int race = 0;
public static void increase() {
race++;
}
private static final int THREAD_COUNT = 20;
public static void main(String[] args) {
Thread[] threads = new Thread[THREAD_COUNT];
for (int i = 0; i < THREAD_COUNT; i++) {
threads[i] = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10000; i++) {
increase();
}
}
});
threads[i].start();
}
// 等待所有累加線程都結(jié)束
for (Thread thread : threads) {
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(race);
}
}
示例:12-1的解決方式一
/**
* 這個程序演示的是:
*
* volatile關(guān)鍵字只能保證可見性,并不能保證原子性(和有序性)
*
* 針對這個程序,想要保證并發(fā)執(zhí)行的結(jié)果符合預(yù)期,可以使用 synchronized關(guān)鍵字實現(xiàn)(但是這種實現(xiàn)方式是重量級的實現(xiàn),效率較低)
*/
public class VolatileTest_12_1_Solution_1 {
public static volatile int race = 0;
public static void increase() {
race++;
}
private static final int THREAD_COUNT = 20;
public static void main(String[] args) {
long start = System.currentTimeMillis();
Thread[] threads = new Thread[THREAD_COUNT];
for (int i = 0; i < THREAD_COUNT; i++) {
threads[i] = new Thread(new Runnable() {
@Override
public void run() {
synchronized (VolatileTest_12_1_Solution_1.class) {
for (int i = 0; i < 10000; i++) {
increase();
}
}
}
});
threads[i].start();
}
// 等待所有累加線程都結(jié)束
for (Thread thread : threads) {
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(race);
long end = System.currentTimeMillis();
System.out.println((end - start));
}
}
示例:12-1的解決方式二
import java.util.concurrent.atomic.AtomicInteger;
/**
* 這個程序演示的是:
* <p>
* volatile關(guān)鍵字只能保證可見性,并不能保證原子性(和有序性)
* <p>
* 針對這個程序,想要保證并發(fā)執(zhí)行的結(jié)果符合預(yù)期,可以使用 synchronized關(guān)鍵字實現(xiàn)(但是這種實現(xiàn)方式是重量級的實現(xiàn),效率較低)
*/
public class VolatileTest_12_1_Solution_2 {
//public static volatile int race = 0;
//public static void increase() {
// race++;
//}
public static AtomicInteger race = new AtomicInteger(0);
public static void increase() {
race.incrementAndGet(); // 原子操作的方法(底層使用CAS指令實現(xiàn))
}
private static final int THREAD_COUNT = 20;
public static void main(String[] args) {
long start = System.currentTimeMillis();
Thread[] threads = new Thread[THREAD_COUNT];
for (int i = 0; i < THREAD_COUNT; i++) {
threads[i] = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10000; i++) {
increase();
}
}
});
threads[i].start();
}
// 等待所有累加線程都結(jié)束
for (Thread thread : threads) {
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(race);
long end = System.currentTimeMillis();
System.out.println((end - start));
}
}
示例:12-3
/**
*
* volatile的使用場景
*
* (書中原話)
* 而在像代碼清單12-3所示的這類場景中就很適合使用volatile變量來控制并發(fā),當(dāng)shutdown()方法被調(diào)用時,
* 能保證所有線程中執(zhí)行的doWork()方法都立即停下來。
*/
public class VolatileTest_12_3 {
private static final int THREADS_COUNT = 3;
public static void main(String[] args) throws InterruptedException {
MyTask myTask = new MyTask();
Thread[] threads = new Thread[THREADS_COUNT];
for (int i = 0; i < THREADS_COUNT; i++) {
threads[i] = new Thread(myTask, "t"+(i+1));
threads[i].start();
}
Thread.sleep(500);
myTask.shutdown();
}
}
class MyTask implements Runnable {
private volatile boolean shutdownRequested;
public void shutdown() {
System.out.println(Thread.currentThread().getName()+"---->");
shutdownRequested = true;
}
@Override
public void run() {
while (!shutdownRequested) {
//try {
// Thread.sleep(500);
//} catch (InterruptedException e) {
// throw new RuntimeException(e);
//}
System.out.println(Thread.currentThread().getName() + " --- do something...");
}
}
}
示例:12-4
import lombok.extern.slf4j.Slf4j;
/**
* 需求:模擬一個A線程用來讀取配置信息,另一個B線程等待A線程把配置信息讀取完成后執(zhí)行后續(xù)任務(wù),
* 其中線程A在讀取完成配置信息后會把一個flag標(biāo)志位由false變?yōu)閠rue, B線程讀取到這個flag標(biāo)志位為true后,才開始執(zhí)行
*/
@Slf4j
public class VolatileTest_12_4 {
public static void main(String[] args) {
// 創(chuàng)建配置信息對象
Configuration configuration = new Configuration();
Thread threadA = new Thread("Thread-A"){
@Override
public void run() {
// 模擬讀取配置信息的耗時操作
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
// 讀取完配置信息后,將其標(biāo)志位改為true
configuration.setConfigLoaded(true);
log.info("Thread-A: Configuration reading completed.");
}
};
Thread threadB = new Thread("Thread-B"){
@Override
public void run() {
// 等待標(biāo)志位為true
while (!configuration.isConfigLoaded()){
// 在標(biāo)志位為false時,線程Thread-B什么都不做
try {
Thread.sleep(50);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
log.info("no no no no...");
}
log.info("Thread-B: Start executing subsequent tasks.");
}
};
threadA.start();
threadB.start();
}
}
// 配置類
class Configuration{
private volatile boolean configLoaded = false;
public boolean isConfigLoaded() {
return configLoaded;
}
public void setConfigLoaded(boolean configLoaded) {
this.configLoaded = configLoaded;
}
}
未完待續(xù)...文章來源地址http://www.zghlxwxcb.cn/news/detail-815474.html
到了這里,關(guān)于《深入理解Java虛擬機:JVM高級特性與最佳實踐(第3版) 周志明》 - 第12章代碼示例的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!