Java 多线程并发面试

Java 是一种广泛使用的编程语言,其内置的多线程支持让开发者能够有效地实现并发编程。然而,随着并发编程的复杂性增加,理解其中的概念至关重要。在本文中,我们将探讨 Java 多线程的基础知识、相关机制以及一些示例代码,并为即将到来的面试做准备。

1. 多线程的基本概念

多线程就是允许一个程序在独立的线程中同时执行多个任务。Java 中的每个线程都是一个 Thread 实例,线程之间可以共享数据。

1.1 创建线程

我们可以通过两种方式创建线程:继承 Thread 类和实现 Runnable 接口。

1.1.1 继承 Thread 类
class MyThread extends Thread {
    public void run() {
        System.out.println("Thread is running");
    }
}

public class Main {
    public static void main(String[] args) {
        MyThread thread = new MyThread();
        thread.start();  // 启动线程
    }
}
1.1.2 实现 Runnable 接口
class MyRunnable implements Runnable {
    public void run() {
        System.out.println("Runnable thread is running");
    }
}

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

1.2 线程的生命周期

Java 线程的生命周期包括 新建可运行阻塞等待终止等状态。

stateDiagram
    [*] --> 新建
    新建 --> 可运行 : start()
    可运行 --> 阻塞 : sleep() 或 wait()
    阻塞 --> 可运行 : notify() 或 sleep 到期
    可运行 --> 终止 : run() 完成

2. 线程同步

多线程程序很容易出现数据不一致的问题,因此需要使用同步机制。Java 提供了 synchronized 关键字和 java.util.concurrent 包中的其他工具。

2.1 使用 synchronized

class Counter {
    private int count = 0;

    public synchronized void increment() {
        count++;
    }

    public int getCount() {
        return count;
    }
}

2.2 使用 ReentrantLock

ReentrantLock 提供了比 synchronized 更灵活的锁定机制。

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

class Counter {
    private int count = 0;
    private Lock lock = new ReentrantLock();

    public void increment() {
        lock.lock();
        try {
            count++;
        } finally {
            lock.unlock();
        }
    }

    public int getCount() {
        return count;
    }
}

3. 线程间通信

在多线程环境下,有时需要线程之间进行通信。Java 提供了 wait()notify()notifyAll() 方法。

class SharedResource {
    private int data;

    public synchronized void produce(int value) {
        data = value;
        notify();  // 唤醒等待的线程
    }

    public synchronized int consume() throws InterruptedException {
        wait();  // 等待生产者生产数据
        return data;
    }
}

4. 使用线程池

使用线程池能够有效地管理和复用线程,避免频繁的创建和销毁。

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadPoolExample {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(2);

        for (int i = 0; i < 5; i++) {
            executor.submit(() -> {
                System.out.println("Running task in: " + Thread.currentThread().getName());
            });
        }

        executor.shutdown();
    }
}

5. 旅行图的使用

在日常的多线程开发中,开发者遵循一定的流程来确保代码的正确性和性能。以下是一个典型的旅行图示例:

journey
    title 多线程编程之旅
    section 学习线程基础
      了解`Thread`类: 5: Me
      练习创建线程: 3: Me
    section 理解同步与通信
      学习`synchronized`: 5: Me
      深入`wait()`与`notify()`: 4: Me
    section 并发工具的使用
      探索`ExecutorService`: 4: Me
      学习`ReentrantLock`: 3: Me

结尾

Java 多线程编程是一个复杂但有趣的领域,通过学习和应用相关概念和工具,开发者能够创建出高效且可扩展的程序。在面试中,掌握多线程的基本概念、生命周期、同步机制、线程间通信以及线程池等知识点是至关重要的。希望这篇文章能帮助你更好地理解 Java 的多线程机制,并在面试中脱颖而出。