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

一、多线程基础概念

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


相关文章

程序员都该知道!Java 30年进化史

1991 年 4 月,Sun 公司启动秘密项目,帕特里克诺顿带领詹姆斯高斯林等 6 人组成 Green 团队,针对消费电子设备研发编程语言。起初尝试改良 C++,但高斯林因繁琐的指针和内存管理问题,决...

Java 8新特性全面解析:让编程更简单、更高效

Java 8新特性全面解析:让编程更简单、更高效引言:Java 8的重要性与革新2014年,Java迎来了一个重要的版本——Java 8。这个版本不仅仅是一次普通的迭代,它更像是Java语言发展史上的...

为什么横行数10年的Java忽然就被鄙视了?

为什么横行数10年的Java忽然就被鄙视了?2012年那会互联网刚刚起步,搭建一个网站动辄几个月到半年,并且找不到程序员,因为很少人会java ,这个时候Java 各种框架出现了,SSH ,SSM,另...

java 进化史1

java 从1996年1月第一个版本诞生,到2022年3月最新的java18,已经经历了27年,整整18个大的版本。很久之前有人就说java要被淘汰,但是java活到现在依然坚挺,不知道java还能活...

Java 11新特性对开发者的影响

Java 11新特性对开发者的影响在这个万物互联的时代,软件开发的重要性日益凸显,而Java作为全球最流行的编程语言之一,每一次版本迭代都牵动着无数开发者的神经。今天,让我们一起聊聊Java 11的新...

Java17,有史以来最快 JDK

就在前不久,Java 又又又更新了,Oracle 正式发布了 Java 开发工具 JDK 最新版 JDK17,新版本提供了不少新特性和功能的增强,而且还是一个 LTS(长期支持)版本,这类 JDK...