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

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

liuian 2025-05-27 15:53 85 浏览

一、多线程基础概念

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年必暴富!——来自一位贫穷但真诚的博主。


相关推荐

163邮箱密码正确就是登不上(163邮箱密码一直错误)

邮箱不能登录或登录异常的原因有很多种哦,如您浏览器“隐私”或“安全”级别设置过高,或用户名、密码输入不正确、较长时间未登录被冻结等都会导致不能登录或登录异常。请您先检查一下哦。解决无法登录的方法有:...

移动硬盘维修费用大概是多少钱

芯片不需要多少钱,但数据恢复就另当别论了。。。如果认识人就帮你换个芯片板,要不了多少钱,如果是硬盘盒的芯片板坏了你就乾脆换个盒子,80左右。如果是硬盘芯片坏了,那就不好办了,没人愿意给你换阿。。。但如...

windows资源管理器停止工作是什么原因

1.在进行重装系统之前,可以先检测一下windows资源管理器停止工作的原因是什么。如果是因为电脑的文件太多了,垃圾堆积导致的停止工作,我们就不需要进行重装系统。我们只需要下载一个360卫士或者其他可...

联想电脑24小时维修热线电话

   1.打开Think.lenovo.com.cn网页,点击登陆。  2.输入用户名密码,点击登陆。  3.点击右上角的:返回个性化首页。  4.点击“咨询与报修”中的“网上报修”。 ...

u盘上的系统怎么安装到电脑上

如果这个u盘是已经制作成为启动盘,可以进入pe系统的话就可以从u盘启动进入到pe系统中进行系统安装!如果你的意思是u盘里直接是操作系统的话,那就在bios设置里直接设定为u盘启动就好了!也可以在pe中...

20年前老笔记本改造升级(比较老的笔记本电脑改装)

答:10年前的笔记本电脑升级改造的方法。1.减少电脑后台程序。电脑和手机也是差不多的,有些软件在关闭之后并没有真正的退出,而是在后台偷偷的运行,这样也是占电脑内存,这样会导致电脑变得越来有。2....

住房公积金贷款计算器(住房公积金贷款计算器在线)

房贷、公积金贷款计算器基本养老保险金计算器基本医疗保险金计算器工伤保险计算器住房公积金缴存计算器养老保险退休金计算器五险一金及税后工资计算器失业保险计算器住房公积金贷款利息怎么计算,具体如下:公积金贷...

电脑开不了机风扇不转(电脑开机风扇转一会停了又继续转)

电脑开不了机,主机风扇转不动,出现这种情况有以下几种可能:1、电源线松了,或电源插板松动,又或者插板不通电。2、主机电源坏了。3、电脑的主板坏了。4、主机面的开关按钮坏了,或者按钮卡住了。解...

网页打不了怎么办(网页打不开是什么原因及解决方法)

浏览器打不开的修复方法:  步骤1、关于浏览器打不开的问题,首先点击电脑桌面左下角“开始”—>“运行”,输入regsvr32jscript.dll后选择“确定”,再次输入regsvr32vb...

ghost文件安装系统方法(ghost如何安装)
  • ghost文件安装系统方法(ghost如何安装)
  • ghost文件安装系统方法(ghost如何安装)
  • ghost文件安装系统方法(ghost如何安装)
  • ghost文件安装系统方法(ghost如何安装)
win10自带文件恢复工具(win10文件恢复工具推荐)

步骤:第一步:打开系统的管理员命令提示符窗口。Windows10系统打开管理员命令提示符窗口有如下几种方法:方法一:在系统桌面左下角的搜索栏输入:CMD,点击:命令提示符,可以打开管理员命令提示符窗口...

电脑本地磁盘c盘满了怎么办(电脑本地磁盘c盘满了如何删除)

当您的电脑本地磁盘C满了时,可能会出现一些问题,例如无法安装新程序、无法保存文件等。以下是一些解决方法:1.删除不需要的文件:可以通过手动删除不需要的文件或使用磁盘清理工具来清理本地磁盘C。在清理磁...

ghost网络克隆详细步骤教程(ghost局域网克隆)
  • ghost网络克隆详细步骤教程(ghost局域网克隆)
  • ghost网络克隆详细步骤教程(ghost局域网克隆)
  • ghost网络克隆详细步骤教程(ghost局域网克隆)
  • ghost网络克隆详细步骤教程(ghost局域网克隆)
傲游浏览器(傲游浏览器app下载)

1、开始——程序——找到遨游——打开,如果能打开说明快捷方式有问题2、362急救箱系统修复、网络修复傲游浏览器曾经是一个备受推荐的浏览器,由于其强大的功能和用户友好的界面,在中国的浏览器市场占有一...

电脑怎么定时关机软件(电脑怎样定时开关机软件)

给电脑设置定时开关机的方法如下:1、点击桌面左下角的开始按钮,打开“控制面板”。2、然后我们点击“系统和安全3、点击下方的“管理工具”。4、再点击“任务计划程序”。5、点击“计划任务程序库”,选择“创...