【Java入门指南 Day14: 并发编程:多线程与同步机制】

一、线程的生命周期与状态转换

线程在其生命周期中会经历多个状态,理解这些状态及其转换对于正确使用多线程至关重要。

线程状态

public class ThreadStates {
    public static void main(String[] args) throws InterruptedException {
        // NEW:新建状态
        Thread thread = new Thread(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        System.out.println("新建状态:" + thread.getState()); // NEW

        // RUNNABLE:运行状态
        thread.start();
        System.out.println("运行状态:" + thread.getState()); // RUNNABLE

        // TIMED_WAITING:计时等待
        Thread.sleep(100);
        System.out.println("等待状态:" + thread.getState()); // TIMED_WAITING

        // 等待线程结束
        thread.join();
        System.out.println("终止状态:" + thread.getState()); // TERMINATED
    }
}

线程的基本操作

public class ThreadOperations {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            // 检查中断状态
            while (!Thread.currentThread().isInterrupted()) {
                // 线程执行的操作
                System.out.println("线程运行中...");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    // 重新设置中断状态
                    Thread.currentThread().interrupt();
                }
            }
        });

        thread.start();
        // 设置优先级
        thread.setPriority(Thread.MAX_PRIORITY);
        // 中断线程
        thread.interrupt();
    }
}

二、线程池的工作原理与使用

线程池通过重用线程来减少线程创建和销毁的开销。

线程池的创建与使用

public class ThreadPoolExample {
    public static void main(String[] args) {
        // 创建固定大小的线程池
        ExecutorService fixedPool = Executors.newFixedThreadPool(5);
        
        // 创建缓存线程池
        ExecutorService cachedPool = Executors.newCachedThreadPool();
        
        // 创建自定义线程池
        ThreadPoolExecutor customPool = new ThreadPoolExecutor(
            2,                      // 核心线程数
            4,                      // 最大线程数
            60L,                    // 空闲线程存活时间
            TimeUnit.SECONDS,       // 时间单位
            new LinkedBlockingQueue<>(100), // 工作队列
            new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略
        );
        
        // 提交任务
        customPool.submit(() -> {
            System.out.println("任务执行中...");
            return "任务结果";
        });
        
        // 关闭线程池
        customPool.shutdown();
    }
}

三、synchronized同步机制

synchronized用于实现线程同步,保证代码块或方法在同一时刻只能被一个线程执行。

synchronized的使用方式

public class SynchronizedExample {
    private int count = 0;
    private final Object lock = new Object();

    // 同步方法
    public synchronized void increment() {
        count++;
    }

    // 同步代码块
    public void incrementBlock() {
        synchronized (lock) {
            count++;
        }
    }

    // 静态同步方法
    public static synchronized void staticMethod() {
        System.out.println("静态同步方法");
    }

    // 实际应用示例
    public void process() {
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                increment();
            }
        });

        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                increment();
            }
        });

        t1.start();
        t2.start();
        
        // 等待线程完成
        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("最终计数: " + count);
    }
}

四、volatile关键字

volatile保证了变量的可见性和有序性,但不保证原子性。

volatile的使用场景

public class VolatileExample {
    // volatile确保可见性
    private volatile boolean flag = false;
    
    public void writer() {
        flag = true; // 修改后其他线程立即可见
    }
    
    public void reader() {
        while (!flag) {
            // 等待flag变为true
        }
    }

    // 双重检查锁定模式
    private static volatile VolatileExample instance;
    
    public static VolatileExample getInstance() {
        if (instance == null) {
            synchronized (VolatileExample.class) {
                if (instance == null) {
                    instance = new VolatileExample();
                }
            }
        }
        return instance;
    }
}

五、原子类

原子类提供了线程安全的操作,无需使用synchronized。

常用原子类操作

public class AtomicExample {
    // 原子整数
    private AtomicInteger counter = new AtomicInteger(0);
    
    // 原子引用
    private AtomicReference<String> reference = 
        new AtomicReference<>("initial");
    
    // 原子数组
    private AtomicIntegerArray array = new AtomicIntegerArray(10);
    
    public void atomicOperations() {
        // 增加并获取
        int value = counter.incrementAndGet();
        
        // 比较并设置
        reference.compareAndSet("initial", "updated");
        
        // 数组操作
        array.getAndAdd(0, 1);
    }

    // 复杂的原子操作
    public void complexAtomicOperation() {
        counter.updateAndGet(x -> x * 2);
        counter.accumulateAndGet(10, Integer::sum);
    }
}

最佳实践建议 💡

  1. 线程创建与管理
    • 优先使用线程池而不是直接创建线程
    • 正确处理线程中断
    • 避免使用Thread.stop()等过时方法
  2. 同步处理
    • 最小化同步范围
    • 优先使用java.util.concurrent包中的工具类
    • 注意死锁预防
  3. 性能优化
    • 合理设置线程池参数
    • 避免过度同步
    • 使用适当的并发容器

常见陷阱提醒 ⚠️

  1. 同步问题
// 错误:非原子操作
private volatile int count = 0;
public void increment() {
    count++; // 非原子操作
}

// 正确:使用原子类
private AtomicInteger count = new AtomicInteger(0);
public void increment() {
    count.incrementAndGet();
}
  1. 线程池问题
// 错误:使用无界队列
ExecutorService executor = new ThreadPoolExecutor(
    10, 10, 0L, TimeUnit.MILLISECONDS,
    new LinkedBlockingQueue<>()); // 可能导致OOM

// 正确:使用有界队列
ExecutorService executor = new ThreadPoolExecutor(
    10, 10, 0L, TimeUnit.MILLISECONDS,
    new LinkedBlockingQueue<>(1000));
  1. 死锁问题
// 可能导致死锁的代码
public class DeadlockExample {
    private final Object lock1 = new Object();
    private final Object lock2 = new Object();
    
    public void method1() {
        synchronized (lock1) {
            synchronized (lock2) {
                // 操作
            }
        }
    }
    
    public void method2() {
        synchronized (lock2) {
            synchronized (lock1) {
                // 操作
            }
        }
    }
}

并发编程是Java中最复杂的主题之一,正确理解和使用这些概念对于开发高性能、可靠的应用程序至关重要。记住要注意线程安全性、性能和死锁预防。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值