Java中的线程同步与阻塞

在多线程编程中,线程的同步和阻塞是非常重要的概念。同步能够帮助我们避免多个线程在访问共享资源时出现竞争条件,而阻塞和唤醒则允许我们灵活地管理线程的执行。本文将带领大家了解如何在Java中实现同步阻塞并唤醒指定线程。

整体流程

我们可以将整个过程分为几个步骤。以下是一个关于实现步骤的表格,清晰地列出了每一步的内容。

步骤 描述
1 创建一个共享资源
2 创建工作线程
3 使用 wait() 阻塞线程
4 使用 notify()notifyAll() 唤醒阻塞线程
5 测试代码并观察各线程的行为

接下来,我们将详细讲解每一个步骤,提供具体的代码示例和注释。

步骤1:创建一个共享资源

我们需要一个共享资源。通常这是一个简单的对象,例如一把锁或条件变量。下面是一个简单的共享资源类:

public class SharedResource {
    private int number = 0;

    public synchronized void increment() {
        number++;
        System.out.println("Incremented: " + number);
        notify(); // 唤醒等待的线程
    }

    public synchronized int getNumber() {
        return number;
    }

    public synchronized void waitForNumber(int target) throws InterruptedException {
        while (number < target) {
            wait(); // 阻塞当前线程
        }
        System.out.println("Reached target: " + target);
    }
}

代码解释

  • increment(): 增加共享变量 number 的值,并在完成后唤醒任何正在等待的线程。
  • getNumber(): 返回当前的 number 值。
  • waitForNumber(int target): 当 number 小于目标值时,调用 wait() 方法阻塞当前线程。

步骤2:创建工作线程

现在我们需要创建两个线程,一个负责增量操作,另一个负责等待操作。

public class WorkerThread extends Thread {
    private SharedResource resource;
    
    public WorkerThread(SharedResource resource) {
        this.resource = resource;
    }

    @Override
    public void run() {
        try {
            if (this.getName().equals("Incrementor")) {
                for (int i = 0; i < 5; i++) {
                    resource.increment(); // 调用共享资源的increment方法
                    Thread.sleep(500); // 模拟一些工作
                }
            } else {
                resource.waitForNumber(3); // 等待number达到3
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

代码解释

  • WorkerThread 类扩展了 Thread,并在构造函数中传入共享资源。
  • run() 方法中执行分支逻辑,一个线程调用 increment(),另一个线程调用 waitForNumber()

步骤3:使用 wait() 阻塞线程

在前面 waitForNumber(int target) 方法中,我们已经实现了使用 wait() 阻塞线程的逻辑。线程会在 number 的值未达到目标值时进入阻塞状态。

步骤4:使用 notify() 唤醒线程

我们在 increment() 方法里调用了 notify(),这是唤醒等待线程的关键。它会唤醒一个正在等待监视器的线程。

步骤5:测试代码并观察各线程的行为

接下来,我们创建一个主类来测试我们的工作线程。

public class Main {
    public static void main(String[] args) {
        SharedResource resource = new SharedResource();

        Thread incrementor = new WorkerThread(resource);
        incrementor.setName("Incrementor");
        Thread waiter = new WorkerThread(resource);
        waiter.setName("Waiter");

        waiter.start(); // 先启动等待线程
        incrementor.start(); // 再启动增量线程
    }
}

代码解释

  • Main 类中,我们创建了 SharedResource 的实例。
  • 创建了两条线程:一个是用来增加数字的(Incrementor),另一个是等待数字达到特定目标的(Waiter)。
  • 首先启动 waiter 线程,然后启动 incrementor 线程。

整体运行流程

  1. 等待线程首先开始,调用 waitForNumber(3) 方法。如果 number 小于3,它会进入阻塞状态。
  2. 随后增量线程开始执行,逐步增加 number 的值,同时调用 notify() 唤醒所有等待的线程。
  3. number 的值达到3时,等待线程被唤醒,继续执行,输出结果。

结尾

通过以上步骤,我们成功实现了线程的同步、阻塞和唤醒机制。本篇文章展示了如何使用 Java 提供的 wait()notify() 方法来管理线程之间的协调与通信。理解这些概念后,您在并发编程中的能力将会大大增强。如果你在今后的项目中需要实现复杂的线程管理,这些基本操作会成为你不可或缺的工具。

希望这篇文章对刚入行的你有所帮助,祝你在Java开发的旅程中获得更多乐趣和成就!如果您还有疑问,不妨在社区里问问,有很多乐意分享经验的人。祝编程愉快!