java线程+synchronized+volatile练习题

1:java线程创建的3种方式

java 复制代码
package com.example.exerciseThread;

import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

public class ExerciseThread {
    public static void main(String[] args) throws Exception {

        System.out.println("========= 方式1:继承Thread ===");
        threadOne();
        //输出结果:========= 方式1:继承Thread ===
        //Thread 方式运行中...


        System.out.println("========= 方式2:实现Runnable ===");
        threadTwo();
        //输出结果:========= 方式2:实现Runnable ===
        //Runnable方式运行中...

        System.out.println("========= 方式3:实现callable ===");
        threadThree();
        //输出结果:========= 方式3:实现callable ===
        //Callable方式运行中...
        //获取结果:Callable返回值
    }


    //方式1:继承Thread(有返回值,可抛异常)
    static void threadOne() {
        Thread thread = new Thread() {
            @Override
            public void run() {
                System.out.println("Thread 方式运行中...");
                // 无返回值,异常需手动处理
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        thread.start();
    }

    //方式2:实现Runnable(无返回值,异常需要手动处理)
    static void threadTwo() {
        Runnable runnable = () -> {
            System.out.println("Runnable方式运行中...");
            // 无返回值,异常需手动处理
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        };
        new Thread(runnable).start();
    }

    //方式3:实现Callable(有返回值,异常自动抛出)
    static void threadThree() throws Exception {
        Callable<String> callable = () -> {
            System.out.println("Callable方式运行中...");
            Thread.sleep(100);
            return "Callable返回值";
        };
        FutureTask<String> task = new FutureTask<>(callable);
        new Thread(task).start();

        String result = task.get();
        System.out.println("获取结果:" + result);
    }

}

2:synchronized练习题

java 复制代码
package com.example.exerciseThread;

public class ExerciseSynchronized {
    //不加锁的计时器
    static class UnsafeCounter {
        private int count = 0;

        public void increment() {
            //非原子性操作:读->改->写
            count++;
        }

        public int getCount() {
            return count;
        }
    }

    //加synchronized的计时器
    static class SafeCounter {
        private int count = 0;

        public synchronized void increment() {
            count++;
        }

        public synchronized int getCount() {
            return count;
        }
    }

    public static void main(String[] args) throws InterruptedException {
        System.out.println("=== 不加synchronized ===");
        testUnsafe();
        // 输出结果:=== 不加synchronized ===
        //期望结果:10000
        //实际结果:9954
        //丢失了:46次

        System.out.println("\n=== 加synchronized ===");
        testSafe();
        // 输出结果:=== 加synchronized ===
        //期望结果:10000
        //实际结果:10000
    }

    static void testUnsafe() throws InterruptedException {
        UnsafeCounter counter = new UnsafeCounter();
        // 10个线程,每个累加1000次
        Thread[] threads = new Thread[10];
        for (int i = 0; i < 10; i++) {
            threads[i] = new Thread(() -> {
                for (int j = 0; j < 1000; j++) {
                    counter.increment();
                }
            });
            threads[i].start();
        }
        for (Thread t : threads) {
            t.join();
        }
        System.out.println("期望结果:10000");
        System.out.println("实际结果:" + counter.getCount());
        System.out.println("丢失了:" + (10000 - counter.getCount()) + "次");
    }

    static void testSafe() throws InterruptedException {
        SafeCounter counter = new SafeCounter();
        // 10个线程,每个累加1000次
        Thread[] threads = new Thread[10];
        for (int i = 0; i < 10; i++) {
            threads[i] = new Thread(() -> {
                for (int j = 0; j < 1000; j++) {
                    counter.increment();
                }
            });
            threads[i].start();
        }
        for (Thread t : threads) {
            t.join();
        }
        System.out.println("期望结果:10000");
        System.out.println("实际结果:" + counter.getCount());
    }


}

结论:

不加锁时(race condition):

线程A: 读 count=0

线程B: 读 count=0 ← 同时读,都是0

线程A: 写 count=1

线程B: 写 count=1 ← 覆盖了A的结果,丢失一次

加 synchronized 后:

线程A: 🔒 获取锁 → 读0 → 写1 → 🔓 释放锁

线程B: 🔒 等待... → 获取锁 → 读1 → 写2 → 🔓 释放锁

↑ 互斥,不会同时执行

3:volatile练习题

java 复制代码
package com.example.exerciseThread;

public class ExerciseVolatile {
    //不加volatile
    static class NoVolatile {
        // 线程可能看不到变化
        private boolean flag = false;

        public void stop() {
            flag = true;
            System.out.println("NoVolatile:已设置 flag=true");
        }

        public boolean getFlag() {
            return flag;
        }
    }

    //加volatile
    static class WithVolatile {
        // 强制从主内存读取
        private volatile boolean flag = false;

        public void stop() {
            flag = true;
            System.out.println("WithVolatile:已设置flag=true");
        }

        public boolean getFlag() {
            return flag;
        }
    }

    public static void main(String[] args) throws InterruptedException {
        System.out.println("=== 不加 volatile(可能永远停不下来) ===");
        testNoVolatile();

        System.out.println("\n=== 加 volatile(立刻停下) ===");
        testWithVolatile();

    }

    static void testNoVolatile() throws InterruptedException {
        NoVolatile demo = new NoVolatile();

        //监控线程:循环检测flag
        Thread monitor = new Thread(() -> {
            int count = 0;
            while (!demo.getFlag()) {
                count++;
                //防止JIT优化掉空循环(加个运算)
                if (count % 1000000 == 0) {
                    System.out.println("NoVolatile:仍在运行...(" + count + ")");
                }
            }
            System.out.println("NoVolatile:检测flag=true,停止!");
        });
        monitor.start();
        //让监控线程先运行
        Thread.sleep(100);

        //主线程修改flag
        demo.stop();

        //等待3秒,看是否能停下
        monitor.join(3000);
        if (monitor.isAlive()) {
            System.out.println("NoVolatile:3秒后仍未停止(线程可能看不到flag变化)");
        }
    }

    static void testWithVolatile() throws InterruptedException {
        WithVolatile demo = new WithVolatile();
        Thread monitor = new Thread(() -> {
            int count = 0;
            while (!demo.getFlag()) {
                count++;
                if (count % 1000000 == 0) {
                    System.out.println("WithVolatile:仍在运行...(" + count + ")");
                }
            }
            System.out.println("WithVolatile:检测到flag=true,立刻停止");
        });
        monitor.start();
        Thread.sleep(100);

        demo.stop();

        monitor.join(3000);
        if (!monitor.isAlive()) {
            System.out.println("WithVolatile:成功停止!");
        }
    }
}

结论:

不加 volatile:

主内存: flag = true

↓ (线程A修改后写入工作内存)

线程B工作内存: flag = false ← ❌ 缓存未刷新,永远读不到 true

加 volatile:

主内存: flag = true

↓ (volatile 强制立即刷新到主内存)

线程B工作内存: flag = true ← ✅ 强制从主内存读取最新值