百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

Java多线程终极指南:从基础到高级应用

zhezhongyun 2025-06-10 04:05 2 浏览

一、多线程基础概念

1.1 进程与线程的区别

对比维度 进程(Process) 线程(Thread) 定义 操作系统资源分配的基本单位 CPU调度的基本单位 内存空间 独立内存空间 共享所属进程的内存空间 通信方式 进程间通信(IPC)较复杂 可直接读写共享变量 创建开销 大(需要分配独立资源) 小(共享进程资源) 稳定性 一个进程崩溃不影响其他进程 一个线程崩溃可能导致整个进程退出

进程(Process)

在Java中,进程是操作系统资源分配的基本单位,具有独立的内存空间。每个Java应用程序运行时都至少有一个进程。进程特点包括:

  • 独立性:拥有独立的地址空间、数据栈等
  • 资源开销大:创建和销毁需要较多系统资源
  • 通信复杂:进程间通信(IPC)需要特殊机制(如管道、套接字等)

线程(Thread)

线程是Java并发编程的基本执行单元,是进程内的一个独立执行流。特点包括:

  • 共享进程资源:同一进程内的线程共享堆内存和方法区
  • 轻量级:创建和切换开销远小于进程
  • 通信简单:可通过共享变量直接通信
  • Java通过java.lang.Thread类和Runnable接口实现多线程

进程 vs 线程:餐厅比喻

想象一家餐厅:

  • 进程就像整个餐厅,有独立的厨房(内存)、收银台(资源)
  • 线程就像餐厅里的服务员,多个服务员共享同一个厨房和收银台

1.2 为什么需要多线程

  1. 提高CPU利用率:当线程I/O阻塞时,其他线程可以继续使用CPU
  2. 更快的响应:GUI程序使用单独线程处理用户输入
  3. 简化建模:每个线程处理单一任务,代码更清晰
  4. 多核优势:现代CPU多核心可真正并行执行线程

日常例子:浏览器同时下载多个文件(每个下载任务一个线程),同时还能响应用户操作(UI线程)。

二、Java线程创建与管理

2.1 创建线程的三种方式

方式1:继承Thread类

// 自定义线程类
class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println("线程执行: " + Thread.currentThread().getName());
    }
}

public class ThreadDemo {
    public static void main(String[] args) {
        MyThread thread = new MyThread();
        thread.start();  // 启动线程
    }
}

方式2:实现Runnable接口

class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("Runnable线程: " + Thread.currentThread().getName());
    }
}

public class RunnableDemo {
    public static void main(String[] args) {
        Thread thread = new Thread(new MyRunnable());
        thread.start();
    }
}

方式3:使用Callable和Future(可获取返回值)

import java.util.concurrent.*;

class MyCallable implements Callable<String> {
    @Override
    public String call() throws Exception {
        Thread.sleep(1000);
        return "Callable结果";
    }
}

public class CallableDemo {
    public static void main(String[] args) throws Exception {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        Future<String> future = executor.submit(new MyCallable());
        
        System.out.println("等待结果...");
        String result = future.get();  // 阻塞直到获取结果
        System.out.println("获取结果: " + result);
        
        executor.shutdown();
    }
}

2.2 三种创建方式对比

对比点 继承Thread类 实现Runnable接口 实现Callable接口 返回值 无 无 有 异常处理 只能在run()内处理 只能在run()内处理 可以通过Future获取 单继承限制 受限于Java单继承 不受限 不受限 线程池支持 不支持 支持 支持 适用场景 简单线程任务 推荐方式 需要返回结果的场景

建议:优先选择实现Runnable接口或Callable接口的方式,避免继承的局限性。

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

3.1 线程的6种状态

Java线程在生命周期中有6种状态(定义在Thread.State枚举中):

  1. **NEW(新建)**:线程被创建但尚未启动
  2. **RUNNABLE(可运行)**:线程正在JVM中执行或等待操作系统资源
  3. **BLOCKED(阻塞)**:等待监视器锁(进入synchronized块)
  4. **WAITING(等待)**:无限期等待其他线程执行特定操作(如wait())
  5. **TIMED_WAITING(计时等待)**:有限时间等待(如sleep())
  6. **TERMINATED(终止)**:线程执行完毕

3.2 状态转换图

NEW ---start()---> RUNNABLE
RUNNABLE ---获取锁---> BLOCKED
RUNNABLE ---wait()---> WAITING
RUNNABLE ---sleep()---> TIMED_WAITING
WAITING ---notify()---> RUNNABLE
TIMED_WAITING ---时间到---> RUNNABLE
RUNNABLE ---run()结束---> TERMINATED

代码示例观察状态

public class ThreadStateDemo {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        
        System.out.println("新建状态: " + thread.getState());  // NEW
        
        thread.start();
        System.out.println("启动后状态: " + thread.getState());  // RUNNABLE
        
        Thread.sleep(100);
        System.out.println("sleep时状态: " + thread.getState());  // TIMED_WAITING
        
        thread.join();
        System.out.println("结束后状态: " + thread.getState());  // TERMINATED
    }
}

四、线程同步与锁机制

4.1 同步问题的产生

概念:当多个线程访问共享资源时,由于线程调度的不确定性,可能导致:

  • 竞态条件(Race Condition):执行结果依赖于线程执行的时序
  • 内存可见性问题:线程对共享变量的修改对其他线程不可见
  • 指令重排序:编译器和处理器优化导致的执行顺序改变

例如:这就像你和室友共用一个冰箱:

  • 你看到最后一瓶可乐(检查条件)
  • 你伸手去拿(执行操作)
  • 同时你室友也伸手
  • 结果要么:1) 你俩各拿到半瓶 2) 系统崩溃 3) 可乐凭空消失

经典问题:银行取款问题

class BankAccount {
    private int balance = 1000;
    
    public void withdraw(int amount) {
        if (balance >= amount) {
            try {
                Thread.sleep(10);  // 模拟处理时间
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            balance -= amount;
            System.out.println(Thread.currentThread().getName() + "取款" + amount + ",余额: " + balance);
        } else {
            System.out.println("余额不足");
        }
    }
}

public class BankDemo {
    public static void main(String[] args) {
        BankAccount account = new BankAccount();
        
        // 两个线程同时取款
        new Thread(() -> account.withdraw(800), "线程1").start();
        new Thread(() -> account.withdraw(800), "线程2").start();
    }
}

输出可能

线程1取款800,余额: 200
线程2取款800,余额: -600

4.2 同步解决方案

方案1:synchronized关键字

特性

  • 内置锁(Intrinsic Lock)/监视器锁(Monitor Lock)
  • 保证原子性(atomicity)和可见性(visibility)
  • 可重入性(Reentrancy):线程可以重复获取已持有的锁
  • 方法级和代码块级两种使用方式

流程

  1. 线程到达同步代码:"我要进这个房间"
  2. JVM门神:"请出示你的锁对象身份证"
  3. 如果没人占用:"请进,记得出来时敲门"
  4. 如果已被占用:"门口排队,别踢门!"
public class house {
    private final Object lock = new Object();
    
    public void use() {
        synchronized(lock) {  // 获取锁
            // 临界区代码
            System.out.println("正在使用中...");
        }  // 释放锁
    }
    
    public synchronized void clean() {  // 方法级同步
        System.out.println("保洁阿姨工作中");
    }
}

方案2:ReentrantLock

特性

  • 可重入
  • 可中断(lockInterruptibly)
  • 尝试获取锁(tryLock)
  • 公平/非公平模式
import java.util.concurrent.locks.ReentrantLock;

class BankAccount {
    private final ReentrantLock lock = new ReentrantLock();
    private int balance = 1000;
    
    public void withdraw(int amount) {
        lock.lock();  // 加锁
        try {
            if (balance >= amount) {
                Thread.sleep(10);
                balance -= amount;
                System.out.println(Thread.currentThread().getName() + "取款" + amount + ",余额: " + balance);
            } else {
                System.out.println("余额不足");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();  // 确保释放锁
        }
    }
}

4.3 synchronized与ReentrantLock对比

对比点 synchronized ReentrantLock 实现机制 JVM层面实现 JDK代码实现 锁获取方式 自动获取释放 需要手动lock/unlock 灵活性 相对不灵活 可尝试获取锁、定时锁、公平锁等 性能 优化后性能接近 高竞争下性能更好 中断响应 不支持 支持lockInterruptibly() 条件队列 单一 可创建多个Condition 适用场景 简单同步需求 复杂同步控制

五、线程间通信

5.1 wait/notify机制

生产者-消费者模型

class MessageQueue {
    private String message;
    private boolean empty = true;
    
    public synchronized String take() {
        while (empty) {
            try {
                wait();  // 等待消息
            } catch (InterruptedException e) {}
        }
        empty = true;
        notifyAll();  // 通知生产者
        return message;
    }
    
    public synchronized void put(String message) {
        while (!empty) {
            try {
                wait();  // 等待消费
            } catch (InterruptedException e) {}
        }
        empty = false;
        this.message = message;
        notifyAll();  // 通知消费者
    }
}

public class ProducerConsumerDemo {
    public static void main(String[] args) {
        MessageQueue queue = new MessageQueue();
        
        // 生产者
        new Thread(() -> {
            String[] messages = {"消息1", "消息2", "消息3"};
            for (String msg : messages) {
                queue.put(msg);
                System.out.println("生产: " + msg);
            }
        }).start();
        
        // 消费者
        new Thread(() -> {
            for (int i = 0; i < 3; i++) {
                String msg = queue.take();
                System.out.println("消费: " + msg);
            }
        }).start();
    }
}

5.2 Condition接口

import java.util.concurrent.locks.*;

class BoundedBuffer {
    final Lock lock = new ReentrantLock();
    final Condition notFull = lock.newCondition();
    final Condition notEmpty = lock.newCondition();
    
    final Object[] items = new Object[100];
    int putptr, takeptr, count;
    
    public void put(Object x) throws InterruptedException {
        lock.lock();
        try {
            while (count == items.length)
                notFull.await();  // 等待不满
            items[putptr] = x;
            if (++putptr == items.length) putptr = 0;
            ++count;
            notEmpty.signal();  // 通知不空
        } finally {
            lock.unlock();
        }
    }
    
    public Object take() throws InterruptedException {
        lock.lock();
        try {
            while (count == 0)
                notEmpty.await();  // 等待不空
            Object x = items[takeptr];
            if (++takeptr == items.length) takeptr = 0;
            --count;
            notFull.signal();  // 通知不满
            return x;
        } finally {
            lock.unlock();
        }
    }
}

六、线程池与Executor框架

6.1 为什么使用线程池

  1. 降低资源消耗:重复利用已创建的线程
  2. 提高响应速度:任务到达时线程已存在
  3. 提高线程可管理性:统一分配、调优和监控
  4. 防止资源耗尽:限制最大线程数

6.2 线程池核心参数

参数 说明 corePoolSize 核心线程数,即使空闲也不会被回收 maximumPoolSize 最大线程数,当工作队列满时创建新线程直到达到此数量 keepAliveTime 非核心线程空闲存活时间 unit 存活时间单位 workQueue 工作队列,保存等待执行的任务 threadFactory 线程工厂,用于创建新线程 handler 拒绝策略,当线程池和工作队列都满时如何处理新任务

6.3 四种常见线程池

// 1. 固定大小线程池
ExecutorService fixedPool = Executors.newFixedThreadPool(5);

// 2. 单线程池(保证顺序执行)
ExecutorService singleThread = Executors.newSingleThreadExecutor();

// 3. 缓存线程池(自动扩容)
ExecutorService cachedPool = Executors.newCachedThreadPool();

// 4. 定时任务线程池
ScheduledExecutorService scheduledPool = Executors.newScheduledThreadPool(3);

6.4 自定义线程池示例

public class ThreadPoolDemo {
    public static void main(String[] args) {
        // 自定义线程池
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
            2,  // 核心线程数
            4,  // 最大线程数
            60, // 空闲时间
            TimeUnit.SECONDS,
            new ArrayBlockingQueue<>(2),  // 任务队列容量2
            new ThreadPoolExecutor.CallerRunsPolicy()  // 拒绝策略
        );
        
        // 提交10个任务
        for (int i = 1; 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();
                }
            });
        }
        
        executor.shutdown();
    }
}

6.5 线程池拒绝策略

策略 行为 AbortPolicy 默认策略,直接抛出RejectedExecutionException CallerRunsPolicy 用调用者所在线程来执行任务 DiscardPolicy 直接丢弃任务,不做任何处理 DiscardOldestPolicy 丢弃队列中最旧的任务,然后尝试提交当前任务

七、高级并发工具类

7.1 CountDownLatch

应用场景:多个线程等待直到所有前置操作完成

public class CountDownLatchDemo {
    public static void main(String[] args) throws InterruptedException {
        CountDownLatch latch = new CountDownLatch(3);  // 需要计数3次
        
        new Thread(() -> {
            System.out.println("任务1完成");
            latch.countDown();  // 计数减1
        }).start();
        
        new Thread(() -> {
            System.out.println("任务2完成");
            latch.countDown();
        }).start();
        
        new Thread(() -> {
            System.out.println("任务3完成");
            latch.countDown();
        }).start();
        
        latch.await();  // 等待计数归零
        System.out.println("所有任务完成,继续主线程");
    }
}

7.2 CyclicBarrier

应用场景:一组线程互相等待到达屏障点

public class CyclicBarrierDemo {
    public static void main(String[] args) {
        CyclicBarrier barrier = new CyclicBarrier(3, () -> {
            System.out.println("所有线程到达屏障,执行屏障动作");
        });
        
        for (int i = 0; i < 3; i++) {
            new Thread(() -> {
                System.out.println(Thread.currentThread().getName() + "到达屏障");
                try {
                    barrier.await();  // 等待其他线程
                } catch (Exception e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "继续执行");
            }).start();
        }
    }
}

7.3 Semaphore

应用场景:控制同时访问特定资源的线程数量

public class SemaphoreDemo {
    public static void main(String[] args) {
        Semaphore semaphore = new Semaphore(3);  // 允许3个线程同时访问
        
        for (int i = 1; i <= 10; i++) {
            new Thread(() -> {
                try {
                    semaphore.acquire();  // 获取许可
                    System.out.println(Thread.currentThread().getName() + "获得许可,执行中...");
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    System.out.println(Thread.currentThread().getName() + "释放许可");
                    semaphore.release();  // 释放许可
                }
            }, "线程" + i).start();
        }
    }
}

7.4 并发工具对比

工具类 作用 关键方法 可重用性 CountDownLatch 一个或多个线程等待其他线程完成操作 countDown(), await() 否 CyclicBarrier 一组线程互相等待到达屏障点 await() 是 Semaphore 控制同时访问特定资源的线程数量 acquire(), release() 是 Phaser 更灵活的屏障,可以动态注册和注销参与方 arrive(), awaitAdvance() 是

八、原子变量与CAS

8.1 原子操作类

Java提供了一系列原子变量类,如AtomicInteger, AtomicLong, AtomicReference等。

public class AtomicDemo {
    public static void main(String[] args) throws InterruptedException {
        AtomicInteger counter = new AtomicInteger(0);
        
        Runnable task = () -> {
            for (int i = 0; i < 1000; i++) {
                counter.incrementAndGet();  // 原子递增
            }
        };
        
        Thread t1 = new Thread(task);
        Thread t2 = new Thread(task);
        
        t1.start();
        t2.start();
        
        t1.join();
        t2.join();
        
        System.out.println("最终计数: " + counter.get());  // 总是2000
    }
}

8.2 CAS原理

CAS(Compare And Swap)是原子变量的实现原理,包含三个操作数:

  • 内存位置(V)
  • 预期原值(A)
  • 新值(B)

当且仅当V的值等于A时,处理器才会用B更新V的值,否则不执行更新。

ABA问题:虽然值还是A,但可能已经被修改过又改回来了。解决方案:使用AtomicStampedReference带版本号。

九、并发集合类

9.1 常用并发集合

接口 非线程安全实现 线程安全实现 List ArrayList CopyOnWriteArrayList Set HashSet CopyOnWriteArraySet, ConcurrentSkipListSet Map HashMap ConcurrentHashMap, ConcurrentSkipListMap Queue LinkedList ArrayBlockingQueue, LinkedBlockingQueue Deque ArrayDeque LinkedBlockingDeque

9.2 ConcurrentHashMap示例

public class ConcurrentHashMapDemo {
    public static void main(String[] args) {
        ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
        
        // 多个线程并发写入
        ExecutorService executor = Executors.newFixedThreadPool(3);
        for (int i = 0; i < 10; i++) {
            final int taskId = i;
            executor.execute(() -> {
                for (int j = 0; j < 100; j++) {
                    String key = "key-" + taskId + "-" + j;
                    map.put(key, j);
                }
            });
        }
        
        executor.shutdown();
        try {
            executor.awaitTermination(1, TimeUnit.MINUTES);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        System.out.println("Map大小: " + map.size());
    }
}

9.3 CopyOnWriteArrayList示例

public class CopyOnWriteDemo {
    public static void main(String[] args) {
        CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
        
        // 一个线程迭代
        new Thread(() -> {
            list.add("A");
            list.add("B");
            Iterator<String> it = list.iterator();
            while (it.hasNext()) {
                System.out.println("迭代: " + it.next());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
        
        // 另一个线程修改
        new Thread(() -> {
            try {
                Thread.sleep(500);
                list.add("C");
                System.out.println("添加了C");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
    }
}

十、Java内存模型(JMM)与happens-before

10.1 JMM核心概念

Java内存模型定义了线程如何与内存交互,主要解决以下问题:

  1. 原子性:基本读写操作是原子的
  2. 可见性:一个线程修改对另一个线程可见
  3. 有序性:防止指令重排序

10.2 happens-before原则

  1. 程序顺序规则:同一线程中的操作,前面的happens-before后面的
  2. 锁规则:解锁happens-before后续加锁
  3. volatile规则:写happens-before后续读
  4. 线程启动规则:线程start()happens-before它的任何操作
  5. 线程终止规则:线程的所有操作happens-before它的终止检测
  6. 中断规则:调用interrupt()happens-before检测到中断
  7. 终结器规则:对象构造happens-before它的finalize()
  8. 传递性:A hb B,B hb C => A hb C

10.3 volatile关键字

public class VolatileDemo {
    private volatile boolean running = true;
    
    public void stop() {
        running = false;
    }
    
    public void run() {
        while (running) {
            // 工作代码
        }
        System.out.println("线程停止");
    }
    
    public static void main(String[] args) throws InterruptedException {
        VolatileDemo demo = new VolatileDemo();
        new Thread(demo::run).start();
        Thread.sleep(1000);
        demo.stop();
    }
}

十一、实战案例分析

11.1 高性能计数器

public class HighPerformanceCounter {
    private final AtomicLong counter = new AtomicLong(0);
    private final LongAdder fastCounter = new LongAdder();
    
    // 简单原子计数器
    public void incrementAtomic() {
        counter.incrementAndGet();
    }
    
    // 高并发优化计数器
    public void incrementAdder() {
        fastCounter.increment();
    }
    
    public long getAtomicCount() {
        return counter.get();
    }
    
    public long getAdderCount() {
        return fastCounter.sum();
    }
    
    public static void main(String[] args) throws InterruptedException {
        HighPerformanceCounter counter = new HighPerformanceCounter();
        
        ExecutorService executor = Executors.newFixedThreadPool(8);
        long start = System.currentTimeMillis();
        
        // 测试AtomicLong性能
        for (int i = 0; i < 1000000; i++) {
            executor.execute(counter::incrementAtomic);
        }
        
        executor.shutdown();
        executor.awaitTermination(1, TimeUnit.MINUTES);
        long atomicTime = System.currentTimeMillis() - start;
        
        executor = Executors.newFixedThreadPool(8);
        start = System.currentTimeMillis();
        
        // 测试LongAdder性能
        for (int i = 0; i < 1000000; i++) {
            executor.execute(counter::incrementAdder);
        }
        
        executor.shutdown();
        executor.awaitTermination(1, TimeUnit.MINUTES);
        long adderTime = System.currentTimeMillis() - start;
        
        System.out.println("AtomicLong结果: " + counter.getAtomicCount() + ", 耗时: " + atomicTime + "ms");
        System.out.println("LongAdder结果: " + counter.getAdderCount() + ", 耗时: " + adderTime + "ms");
    }
}

11.2 限流器实现

public class RateLimiter {
    private final Semaphore semaphore;
    private final int maxPermits;
    private final long period;
    private ScheduledExecutorService scheduler;
    
    public RateLimiter(int permits, long period, TimeUnit unit) {
        this.semaphore = new Semaphore(permits);
        this.maxPermits = permits;
        this.period = unit.toMillis(period);
        this.scheduler = Executors.newScheduledThreadPool(1);
        
        scheduler.scheduleAtFixedRate(() -> {
            int current = semaphore.availablePermits();
            if (current < maxPermits) {
                semaphore.release(maxPermits - current);
            }
        }, 0, this.period, TimeUnit.MILLISECONDS);
    }
    
    public boolean tryAcquire() {
        return semaphore.tryAcquire();
    }
    
    public void acquire() throws InterruptedException {
        semaphore.acquire();
    }
    
    public void shutdown() {
        scheduler.shutdown();
    }
    
    public static void main(String[] args) throws InterruptedException {
        // 每秒最多5个请求
        RateLimiter limiter = new RateLimiter(5, 1, TimeUnit.SECONDS);
        
        // 模拟10个请求
        for (int i = 1; i <= 10; i++) {
            if (limiter.tryAcquire()) {
                System.out.println("处理请求 " + i);
            } else {
                System.out.println("限流请求 " + i);
            }
            Thread.sleep(100);
        }
        
        limiter.shutdown();
    }
}

十二、常见问题与最佳实践

12.1 多线程常见问题

  1. 死锁:多个线程互相等待对方释放锁
  2. 避免方法:按固定顺序获取锁,使用tryLock()设置超时
  3. 活锁:线程不断改变状态但无法继续执行
  4. 避免方法:引入随机性,如随机等待时间
  5. 线程饥饿:某些线程长期得不到执行
  6. 解决方法:使用公平锁,合理设置线程优先级

12.2 最佳实践

  1. 尽量使用高层并发工具:如线程池、并发集合
  2. 优先使用不可变对象:避免同步问题
  3. 缩小同步范围:只同步必要的代码块
  4. 避免过早优化:先保证正确性,再考虑性能
  5. 考虑使用并行流:Java 8+的parallelStream()
  6. 合理设置线程池大小
  7. CPU密集型:CPU核心数+1
  8. IO密集型:CPU核心数 × (1 + 平均等待时间/平均计算时间)

12.3 性能调优建议

  1. 减少锁竞争
  2. 缩小同步块
  3. 使用读写锁(ReentrantReadWriteLock)
  4. 使用分段锁(如ConcurrentHashMap)
  5. 避免上下文切换
  6. 合理设置线程数
  7. 使用协程(如Quasar库)
  8. 使用无锁数据结构
  9. Atomic类
  10. LongAdder
  11. ConcurrentLinkedQueue

总结

Java多线程编程是Java高级开发的核心技能之一。本文从基础概念到高级应用,全面介绍了Java多线程的各个方面:

  1. 线程创建与生命周期管理
  2. 同步机制与锁优化
  3. 线程间通信方式
  4. 线程池与Executor框架
  5. 高级并发工具类
  6. 原子变量与CAS
  7. 并发集合类
  8. Java内存模型
  9. 实战案例与最佳实践

Java 多线程像一群疯跑的小怪兽,协调好就齐力通关,没控制住,程序直接被它们折腾得 “脑震荡”!

★ 收藏转发的人,2024年必暴富!——来自一位贫穷但真诚的博主。


相关推荐

屏幕属性详解:DCI-P3、对比度、色域、Nit

屏幕属性详解:DCI-P3、对比度、色域、Nit---一、DCI-P3(色域标准)1.定义DCI-P3是由美国电影工业制定的广色域标准,覆盖CIE1931色彩空间的约96%,尤其强化红色和绿...

Qt属性系统(Qt Property System)(qt的pro文件属性说明)

Qt提供了巧妙的属性系统,它与某些编译器支持的属性系统相似。然而,作为平台和编译器无关的库,Qt不能够依赖于那些非标准的编译器特性,比如__property或者[property]。Qt的解决方案...

用 Cursor 开发 10 +项目后,汇总了40 多条提示词

每次跟新手讲解Cursor的使用技巧时,他们总会说:"哎呀,这工具好是好,就是不知道该怎么跟它对话..."是的,不少小伙伴都在为这个困扰:手握着强大的AI编程工具,却像拿着一把...

Excel常用技能分享与探讨(5-宏与VBA简介 VBA与数据库)

在VBA(VisualBasicforApplications)中使用数据库(如Access、SQLServer、MySQL等)具有以下优点,适用于需要高效数据管理和复杂业务逻辑的场景:1....

汽车诊断协议J1850-VPW 测试(汽车诊断协议工程师干啥的)

硬件说明:MCU:GD32C103120M,128K,32kRAM.输入:USB5V.OBD功能口定义:OBD(2,10)VPWM、OBD7(K线)、OBD6(CANH)、OBD14(...

ssl证书有哪些类型?有什么区别?(ssl证书的区别)

以下是**Windows服务器常用快捷命令大全(100条)**,涵盖系统管理、网络诊断、安全维护、文件操作等场景,适合管理员快速操作和故障排查:---###**一、系统信息与配置**1.**`s...

嵌入式工程师竟然看不懂这些专业语句,那真别怪人说你菜

本文出自公众号:硬件笔记本,原创文章,转载请注明出处AASIC(专用集成电路)Application-SpecificIntegratedCircuit.Apieceofcustom-de...

同星提供SecOC信息安全解决方案(上海同星)

需求背景在传统的汽车电子结构中,车内的电控单元(ECU)数量和复杂性受到限制,通信带宽也受到限制。因此,人们普遍认为车内各个ECU之间的通信是可靠的。只要ECU节点接收到相应的消息,就会对其进行处理。...

H3C MSR系列路由器EAA监控策略配置举例

1简介本文档介绍使用EAA监控策略进行网络监控的典型配置举例。2配置前提本文档适用于使用ComwareV7软件版本的MSR系列路由器,如果使用过程中与产品实际情况有差异,请参考相关产品手册,或以...

网卡DM9000裸机驱动开发详解(网卡驱动9462)

一、网卡1.概念网卡是一块被设计用来允许计算机在计算机网络上进行通讯的计算机硬件。由于其拥有MAC地址,因此属于OSI模型的第2层。它使得用户可以通过电缆或无线相互连接。每一个网卡都有一个被称为MA...

如何检验自己的手机有没有问题,实操干货!包学会

此贴供已购买二手苹果或正打算购买的朋友参考,已入新机的朋友也可以验一下你的手机有没有问题。无废话,直接上干货以小编随机挑的一台12为例1.外观:拿到手机先看整体外观,是否与商家描述的外观一致,磕碰和划...

再不看就删了!超详细的Ribbon源码解析

Ribbon简介什么是Ribbon?Ribbon是springcloud下的客户端负载均衡器,消费者在通过服务别名调用服务时,需要通过Ribbon做负载均衡获取实际的服务调用地址,然后通过httpcl...

细数ThreadLocal三大坑,内存泄露仅是小儿科

我在参加CodeReview的时候不止一次听到有同学说:我写的这个上下文工具没问题,在线上跑了好久了。其实这种想法是有问题的,ThreadLocal写错难,但是用错就很容易,本文将会详细总结Thre...

微服务架构下的Java服务监控:让程序“健康自检”不再难

微服务架构下的Java服务监控:让程序“健康自检”不再难引言:为什么需要服务监控?在微服务架构的世界里,我们的系统由众多小型且独立的服务组成。想象一下,这些服务就像一群跳舞的小精灵,在各自的舞台上表演...

6. 并发编程(并发编程模型)

本章深入解析Go语言并发编程核心机制,涵盖调度原理、通信模式及工程实践,结合性能优化与陷阱规避策略。6.1Goroutine基础6.1.1创建与调度//启动goroutinegofunc()...