Java多线程使用基础

127 阅读1分钟

容易忽略的知识

  1. 在32位系统中,未使用 volatile 关键字声明的 long/double 类型不是原子写操作。
  2. 在方法声明处添加 synchronized 关键字不是锁方法,而是锁当前类的对象。
  3. 创建太多的线程会导致程序执行效率降低。

线程的生命周期

图片.png

图片来源《Java 多线程编程核心技术》

使用多线程

继承Thread类

public class XXXXThread extends Thread {

    @Override
    public void run() {
        // TODO
    }

    public static void main(String[] args) {
        XXXXThread thread = new XXXXThread();
        
        thread.start();
    }

}

实现Runnable接口

public class XXXXThread implements Runnable {

    @Override
    public void run() {
        // TODO
    }

    public static void main(String[] args) {
        Runnable runnable = new XXXXThread();
        Thread thread = new Thread(runnable);

        thread.start();
    }

}

获取多个线程任务的结果

ExecutorService executorService = Executors.newFixedThreadPool(10);
CompletionService<Object> completionService = new ExecutorCompletionService<>(executorService);

// 定义任务
Callable<Object> callable = () -> {
    long sleepTime = (long) (Math.random() * 5000);
    Thread.sleep(sleepTime);

    return sleepTime;
};

// 执行任务
for (int i = 0; i < 10; i++) {
    completionService.submit(callable);
}

// 获取结果
for (int i = 0; i < 10; i++) {
    System.out.println("result: " + completionService.take().get());
}

实用的线程类

ReentrantLock类

因为 synchronized 是Java语言层面提供的语法,所以我们不需要考虑异常,而 ReentrantLock 是Java代码实现的锁,我们就必须先获取锁,然后在 finally 中正确释放锁。

Condition类

Condition 提供的 await、signal、signalAll 原理和 synchronized 锁对象的 wait、notify、notifyAll 是一致的,并且其行为也是一样的。

ReadWriteLock类

只允许一个线程写入(其他线程既不能写入也不能读取)。没有写入时,多个线程允许同时读。

StampedLock类

StampedLock 提供了乐观读锁,可取代 ReadWriteLock 以进一步提升并发性能。StampedLock 是不可重入锁。

Future类

对线程池提交一个 Callable 任务,可以获得一个 Future 对象。可以用 Future 在将来某个时刻获取结果。

线程的状态

图片.png

图片来源《Java 多线程编程核心技术》

状态描述
NEW至今尚未启动的线程
RUNNABLE执行的线程
BLOCKED受阻塞并等待某个锁的线程
WAITING等待另一个线程来执行某一特定操作的线程
TIMED_WAITING等待指定时间的线程
TERMINATED已退出的线程