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 ← ✅ 强制从主内存读取最新值