背景
最近在看《深入理解Java虚拟机:JVM高级特性与最佳实践(第3版) 周志明》这本书,书中有些代码示例是为了让读者理解作者表达的意思,但不是完整的代码示例,所以针对这些不完整的代码,自己动手写出完整的代码示例。
说明
(1)在看这本书的同学,可以拿我这里的示例代码做个参考,并欢迎提出意见和建议;
(2)示例的标号,是和书中的代码示例标号相对应的。文章来源:https://www.toymoban.com/news/detail-815474.html
第12章 - 代码
示例:12-1
/**
* 这个程序演示的是:《深入理解JVM》(周志明 第三版) 代码清党12-1 volatile运算
*
* volatile关键字只能保证可见性,并不能保证原子性(和有序性)
* 因为程序输出的结果有不等于200000的情况发生
*/
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();
}
// 等待所有累加线程都结束
for (Thread thread : threads) {
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(race);
}
}
示例:12-1的解决方式一
/**
* 这个程序演示的是:
*
* volatile关键字只能保证可见性,并不能保证原子性(和有序性)
*
* 针对这个程序,想要保证并发执行的结果符合预期,可以使用 synchronized关键字实现(但是这种实现方式是重量级的实现,效率较低)
*/
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();
}
// 等待所有累加线程都结束
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关键字只能保证可见性,并不能保证原子性(和有序性)
* <p>
* 针对这个程序,想要保证并发执行的结果符合预期,可以使用 synchronized关键字实现(但是这种实现方式是重量级的实现,效率较低)
*/
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指令实现)
}
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();
}
// 等待所有累加线程都结束
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变量来控制并发,当shutdown()方法被调用时,
* 能保证所有线程中执行的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线程把配置信息读取完成后执行后续任务,
* 其中线程A在读取完成配置信息后会把一个flag标志位由false变为true, B线程读取到这个flag标志位为true后,才开始执行
*/
@Slf4j
public class VolatileTest_12_4 {
public static void main(String[] args) {
// 创建配置信息对象
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);
}
// 读取完配置信息后,将其标志位改为true
configuration.setConfigLoaded(true);
log.info("Thread-A: Configuration reading completed.");
}
};
Thread threadB = new Thread("Thread-B"){
@Override
public void run() {
// 等待标志位为true
while (!configuration.isConfigLoaded()){
// 在标志位为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;
}
}
未完待续...文章来源地址https://www.toymoban.com/news/detail-815474.html
到了这里,关于《深入理解Java虚拟机:JVM高级特性与最佳实践(第3版) 周志明》 - 第12章代码示例的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!