一篇文章然你搞懂Java多线程知识体系。

58 阅读5分钟

一、多线程基础概念

1. 进程与线程的区别

  • 进程:操作系统资源分配的基本单位(拥有独立内存空间)
  • 线程:CPU调度的基本单位(共享进程内存空间)

2. 线程的创建方式

方式1:继承Thread类

	public class MyThread extends Thread {

	    @Override

	    public void run() {

	        System.out.println("继承Thread方式运行,线程名:" + Thread.currentThread().getName());

	    }

	}

	 

	// 启动方式

	new MyThread().start(); // 必须调用start()而非run()

方式2:实现Runnable接口(推荐)

	public class MyRunnable implements Runnable {

	    @Override

	    public void run() {

	        System.out.println("实现Runnable方式运行,线程名:" + Thread.currentThread().getName());

	    }

	}

	 

	// 启动方式

	new Thread(new MyRunnable()).start();

方式3:实现Callable接口(带返回值)

	import java.util.concurrent.*;

	 

	public class MyCallable implements Callable<Integer> {

	    @Override

	    public Integer call() throws Exception {

	        System.out.println("Callable方式运行");

	        return 100;

	    }

	}

	 

	// 启动方式

	FutureTask<Integer> futureTask = new FutureTask<>(new MyCallable());

	new Thread(futureTask).start();

	Integer result = futureTask.get(); // 阻塞获取结果

3. 线程的生命周期

	NEW → RUNNABLE → (BLOCKED/WAITING/TIMED_WAITING) → TERMINATED
  • NEW:新建状态
  • RUNNABLE:就绪/运行状态
  • BLOCKED:等待锁释放
  • WAITING:调用Object.wait()等方法进入无限等待
  • TIMED_WAITING:调用sleep()等方法进入有限时间等待
  • TERMINATED:线程结束

二、线程同步机制

1. synchronized关键字

对象锁(实例方法)

	public class Counter {

	    private int count = 0;

	    

	    public synchronized void increment() { // 对象锁

	        count++;

	    }

	}

类锁(静态方法)

	public class StaticCounter {

	    private static int count = 0;

	    

	    public static synchronized void increment() { // 类锁

	        count++;

	    }

	}

同步代码块

	public class BlockCounter {

	    private final Object lock = new Object();

	    private int count = 0;

	    

	    public void increment() {

	        synchronized (lock) { // 指定锁对象

	            count++;

	        }

	    }

	}

2. ReentrantLock可重入锁

	import java.util.concurrent.locks.ReentrantLock;

	 

	public class ReentrantLockDemo {

	    private final ReentrantLock lock = new ReentrantLock();

	    private int count = 0;

	    

	    public void increment() {

	        lock.lock(); // 获取锁

	        try {

	            count++;

	        } finally {

	            lock.unlock(); // 必须释放锁

	        }

	    }

	}

3. 读写锁(ReadWriteLock)

	import java.util.concurrent.locks.ReentrantReadWriteLock;

	 

	public class Cache {

	    private final Map<String, Object> map = new HashMap<>();

	    private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();

	    

	    public Object get(String key) {

	        rwLock.readLock().lock();

	        try {

	            return map.get(key);

	        } finally {

	            rwLock.readLock().unlock();

	        }

	    }

	    

	    public void put(String key, Object value) {

	        rwLock.writeLock().lock();

	        try {

	            map.put(key, value);

	        } finally {

	            rwLock.writeLock().unlock();

	        }

	    }

	}

三、线程通信机制

1. wait()/notify()方法

	public class WaitNotifyDemo {

	    private static final Object lock = new Object();

	    private static boolean flag = false;

	    

	    public static void main(String[] args) {

	        // 等待线程

	        new Thread(() -> {

	            synchronized (lock) {

	                while (!flag) {

	                    try {

	                        System.out.println("等待线程进入等待状态");

	                        lock.wait(); // 释放锁并等待

	                    } catch (InterruptedException e) {

	                        e.printStackTrace();

	                    }

	                }

	                System.out.println("等待线程被唤醒");

	            }

	        }).start();

	        

	        // 通知线程

	        new Thread(() -> {

	            try {

	                Thread.sleep(2000);

	            } catch (InterruptedException e) {

	                e.printStackTrace();

	            }

	            synchronized (lock) {

	                flag = true;

	                lock.notifyAll(); // 唤醒所有等待线程

	                System.out.println("通知线程发送通知");

	            }

	        }).start();

	    }

	}

2. Condition对象(更灵活的线程通信)

	import java.util.concurrent.locks.*;

	 

	public class ConditionDemo {

	    private final Lock lock = new ReentrantLock();

	    private final Condition condition = lock.newCondition();

	    private boolean flag = false;

	    

	    public void await() throws InterruptedException {

	        lock.lock();

	        try {

	            while (!flag) {

	                System.out.println("等待线程进入等待状态");

	                condition.await(); // 必须配合lock使用

	            }

	            System.out.println("等待线程被唤醒");

	        } finally {

	            lock.unlock();

	        }

	    }

	    

	    public void signal() throws InterruptedException {

	        lock.lock();

	        try {

	            flag = true;

	            condition.signalAll(); // 唤醒所有等待线程

	            System.out.println("通知线程发送通知");

	        } finally {

	            lock.unlock();

	        }

	    }

	}

四、线程池技术

1. Executor框架核心类

	import java.util.concurrent.*;

	 

	public class ThreadPoolDemo {

	    public static void main(String[] args) {

	        // 1. 创建线程池

	        ExecutorService executor = Executors.newFixedThreadPool(3);

	        

	        // 2. 提交任务

	        for (int i = 0; i < 10; i++) {

	            final int taskId = i;

	            executor.execute(() -> {

	                System.out.println("执行任务" + taskId + ",线程:" + Thread.currentThread().getName());

	                try {

	                    Thread.sleep(1000);

	                } catch (InterruptedException e) {

	                    e.printStackTrace();

	                }

	            });

	        }

	        

	        // 3. 关闭线程池

	        executor.shutdown(); // 优雅关闭

	        // executor.shutdownNow(); // 立即关闭

	    }

	}

2. ThreadPoolExecutor参数详解

	// 核心线程数:5

	// 最大线程数:10

	// 空闲线程存活时间:60秒

	// 任务队列:容量为100的LinkedBlockingQueue

	// 线程工厂:自定义线程命名

	// 拒绝策略:当队列满时直接抛出异常

	ThreadPoolExecutor executor = new ThreadPoolExecutor(

	    5, 

	    10, 

	    60, 

	    TimeUnit.SECONDS,

	    new LinkedBlockingQueue<>(100),

	    r -> new Thread(r, "custom-thread-" + r.hashCode()),

	    new ThreadPoolExecutor.AbortPolicy()

	);

3. 常用拒绝策略

  • AbortPolicy:默认策略,直接抛出RejectedExecutionException
  • CallerRunsPolicy:由调用线程执行该任务
  • DiscardPolicy:直接丢弃任务
  • DiscardOldestPolicy:丢弃队列中最旧的任务

五、并发工具类

1. CountDownLatch(倒计时门闩)

	import java.util.concurrent.*;

	 

	public class CountDownLatchDemo {

	    public static void main(String[] args) throws InterruptedException {

	        CountDownLatch latch = new CountDownLatch(3); // 等待3个线程完成

	        

	        for (int i = 0; i < 3; i++) {

	            final int workerId = i;

	            new Thread(() -> {

	                try {

	                    Thread.sleep(1000 * (workerId + 1));

	                    System.out.println("Worker " + workerId + " 完成工作");

	                } catch (InterruptedException e) {

	                    e.printStackTrace();

	                } finally {

	                    latch.countDown(); // 计数减1

	                }

	            }).start();

	        }

	        

	        System.out.println("主线程等待所有Worker完成...");

	        latch.await(); // 阻塞直到计数为0

	        System.out.println("所有Worker完成,主线程继续执行");

	    }

	}

2. CyclicBarrier(循环屏障)

	import java.util.concurrent.*;

	 

	public class CyclicBarrierDemo {

	    public static void main(String[] args) {

	        CyclicBarrier barrier = new CyclicBarrier(3, () -> {

	            System.out.println("所有参与者到达屏障点,开始下一阶段");

	        });

	        

	        for (int i = 0; i < 3; i++) {

	            final int riderId = i;

	            new Thread(() -> {

	                try {

	                    System.out.println("骑手" + riderId + "准备就绪");

	                    Thread.sleep(1000 * (riderId + 1));

	                    System.out.println("骑手" + riderId + "到达屏障点");

	                    barrier.await(); // 等待其他线程

	                    System.out.println("骑手" + riderId + "继续比赛");

	                } catch (Exception e) {

	                    e.printStackTrace();

	                }

	            }).start();

	        }

	    }

	}

3. Semaphore(信号量)

	import java.util.concurrent.*;

	 

	public class SemaphoreDemo {

	    public static void main(String[] args) {

	        Semaphore semaphore = new Semaphore(2); // 允许2个线程同时访问

	        

	        for (int i = 0; i < 5; i++) {

	            final int carId = i;

	            new Thread(() -> {

	                try {

	                    semaphore.acquire(); // 获取许可

	                    System.out.println("汽车" + carId + "进入停车场");

	                    Thread.sleep(2000);

	                    System.out.println("汽车" + carId + "离开停车场");

	                } catch (InterruptedException e) {

	                    e.printStackTrace();

	                } finally {

	                    semaphore.release(); // 释放许可

	                }

	            }).start();

	        }

	    }

	}

六、原子类与并发集合

1. Atomic原子类

	import java.util.concurrent.atomic.*;

	 

	public class AtomicDemo {

	    private static AtomicInteger atomicCount = new AtomicInteger(0);

	    private static int normalCount = 0;

	    

	    public static void main(String[] args) throws InterruptedException {

	        // 原子类线程安全

	        Thread t1 = new Thread(() -> {

	            for (int i = 0; i < 10000; i++) {

	                atomicCount.incrementAndGet();

	            }

	        });

	        

	        // 普通变量非线程安全

	        Thread t2 = new Thread(() -> {

	            for (int i = 0; i < 10000; i++) {

	                normalCount++;

	            }

	        });

	        

	        t1.start();

	        t2.start();

	        t1.join();

	        t2.join();

	        

	        System.out.println("AtomicInteger结果: " + atomicCount); // 20000

	        System.out.println("普通int结果: " + normalCount); // 可能是小于20000的随机值

	    }

	}

2. 并发集合类

	import java.util.concurrent.*;

	 

	public class ConcurrentCollectionDemo {

	    public static void main(String[] args) {

	        // ConcurrentHashMap

	        ConcurrentHashMap<String, String> map = new ConcurrentHashMap<>();

	        map.put("key1", "value1");

	        

	        // CopyOnWriteArrayList(适合读多写少场景)

	        CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();

	        list.add("item1");

	        

	        // ConcurrentLinkedQueue

	        ConcurrentLinkedQueue<String> queue = new ConcurrentLinkedQueue<>();

	        queue.offer("task1");

	    }

	}

七、性能优化建议

  1. 合理设置线程池参数

    • CPU密集型任务:核心线程数 ≈ CPU核心数
    • IO密集型任务:核心线程数 ≈ CPU核心数 * 2
  2. 避免锁的滥用

    • 尽量缩小同步代码块范围
    • 优先使用不可变对象
    • 考虑使用CAS(Compare-And-Swap)操作
  3. 使用并发工具替代wait/notify

    • 优先使用CountDownLatch/CyclicBarrier等工具类
  4. 合理使用volatile关键字

    • 保证可见性但不保证原子性
    • 适用于状态标记等简单场景

八、总结

Java多线程编程是一个庞大而复杂的领域,本文系统梳理了:

  1. 线程创建与生命周期管理
  2. 同步机制(synchronized/Lock)
  3. 线程通信(wait/notify/Condition)
  4. 线程池技术(Executor框架)
  5. 并发工具类(CountDownLatch等)
  6. 原子类与并发集合

在实际开发中,应根据具体场景选择合适的并发控制手段,既要保证线程安全,又要避免过度同步导致的性能问题。建议通过JMH等工具进行性能测试,找到最优方案。

希望本文能为Java多线程学习者提供清晰的实践指南,后续将分享更多高并发场景的实战案例。