Android线程间的等待与协调

在Android的开发中,线程的使用是非常常见的,特别是在需要处理耗时操作时。实际上,多个线程之间的协作与同步是构建应用程序的基石之一。在本篇文章中,我们将探讨如何让一个线程等待另一个线程执行完毕,并给出相应的代码示例以及流程图和类图。

线程的基本概念

线程是执行代码的基本单位。在Android中,UI线程负责更新用户界面,而耗时操作应该放在子线程中执行。然而,有时我们需要在一个线程中等待另一个线程完成某项操作,比如执行网络请求,处理数据等,才能继续后续操作。

常用的线程同步方式

有多种技术可以用来实现线程的同步。在这里,我们将主要探讨以下几种方式:

  1. join()方法
  2. CountDownLatch
  3. Semaphore
  4. FutureTask

接下来,我们将逐一介绍这些方法。

1. 使用join()方法

join()方法用于使当前线程等待调用此方法的线程执行结束。以下是一个简单的示例:

class TaskOne extends Thread {
    @Override
    public void run() {
        try {
            Thread.sleep(2000); // 模拟耗时操作
            System.out.println("Task One completed");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

class TaskTwo extends Thread {
    private Thread threadToJoin;

    public TaskTwo(Thread threadToJoin) {
        this.threadToJoin = threadToJoin;
    }

    @Override
    public void run() {
        try {
            threadToJoin.join(); // 等待 TaskOne 执行完
            System.out.println("Task Two starts after Task One");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

public class ThreadDemo {
    public static void main(String[] args) {
        TaskOne taskOne = new TaskOne();
        TaskTwo taskTwo = new TaskTwo(taskOne);
        
        taskOne.start();
        taskTwo.start();
    }
}

2. 使用CountDownLatch

CountDownLatch 是一个更灵活的线程同步工具。这使得一个线程可以等待若干个线程完成任务。以下是示例:

import java.util.concurrent.CountDownLatch;

class WorkerThread extends Thread {
    private CountDownLatch latch;

    public WorkerThread(CountDownLatch latch) {
        this.latch = latch;
    }

    @Override
    public void run() {
        try {
            Thread.sleep(2000);
            System.out.println(Thread.currentThread().getName() + " completed");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            latch.countDown(); // 结束时减一
        }
    }
}

public class CountDownLatchDemo {
    public static void main(String[] args) {
        int threadCount = 3;
        CountDownLatch latch = new CountDownLatch(threadCount);
        
        for (int i = 0; i < threadCount; i++) {
            new WorkerThread(latch).start();
        }

        try {
            latch.await(); // 等待所有线程完成
            System.out.println("All threads completed");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

3. 使用Semaphore

Semaphore主要用于控制对共享资源的访问,但也可以用作线程间的协调。示例代码如下:

import java.util.concurrent.Semaphore;

class MySemaphoreThread extends Thread {
    private Semaphore semaphore;

    public MySemaphoreThread(Semaphore semaphore) {
        this.semaphore = semaphore;
    }

    @Override
    public void run() {
        try {
            Thread.sleep(2000);
            System.out.println(Thread.currentThread().getName() + " finished work");
            semaphore.release();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

public class SemaphoreDemo {
    public static void main(String[] args) {
        Semaphore semaphore = new Semaphore(0);

        for (int i = 0; i < 3; i++) {
            new MySemaphoreThread(semaphore).start();
        }

        try {
            semaphore.acquire(3); // 等待3个线程完成
            System.out.println("All threads have finished");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

4. 使用FutureTask

FutureTask是一个实现了Runnable接口的类,可以用于获取可能在将来的某个时间产生的计算结果。

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

class MyCallable implements Callable<String> {
    @Override
    public String call() throws Exception {
        Thread.sleep(2000);
        return "Task completed";
    }
}

public class FutureTaskDemo {
    public static void main(String[] args) {
        FutureTask<String> futureTask = new FutureTask<>(new MyCallable());
        new Thread(futureTask).start();

        try {
            System.out.println("Waiting for task to complete...");
            String result = futureTask.get(); // 阻塞等待结果
            System.out.println(result);
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
    }
}

流程图

以下是一个简单的流程图,用于描述一个线程等待另一个线程的执行过程:

flowchart TD
    A[主线程] -->|启动| B[子线程1]
    B -->|完成| C[主线程继续执行]

类图

为了更好地描述类之间的关系,下面是类图示例,说明哪个类负责哪个线程的执行。

classDiagram
    class MainThread {
        +main(args: String[])
    }

    class TaskOne {
        +run()
    }

    class TaskTwo {
        +run()
    }

    MainThread --> TaskOne
    MainThread --> TaskTwo
    TaskTwo --> TaskOne

总结

在Android中,线程间的协调与等待是一个非常重要的主题。通过 join(), CountDownLatch, Semaphore, 和 FutureTask等多种方式,可以实现线程间的有效同步。在编写多线程应用时,我们应关注这些机制,以确保应用的稳定性与正确性。希望本文能为您深入理解这一领域提供帮助。