多线程按顺序执行实现方式

108 阅读3分钟

在多线程编程中,有时候需要让多个线程按照一定的顺序执行。以下是几种实现多线程按顺序执行的方式:

  1. 使用 join 方法: 可以在一个线程中调用另一个线程的 join() 方法,这会使得当前线程等待被调用线程执行完成后再继续执行。通过不同线程之间的 join 调用,可以实现多个线程的顺序执行。
    public class ThreadSequenceExample {
    public static void main(String[] args) {
        Thread thread1 = new Thread(() -> {
            System.out.println("Thread 1 is running");
        });

        Thread thread2 = new Thread(() -> {
            try {
                thread1.join(); // 等待thread1执行完毕
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("Thread 2 is running");
        });

        Thread thread3 = new Thread(() -> {
            try {
                thread2.join(); // 等待thread2执行完毕
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("Thread 3 is running");
        });

        thread1.start();
        thread2.start();
        thread3.start();
    }
}
  1. 使用 CountDownLatch: CountDownLatch 是 Java.util.concurrent 包中的一个同步工具类,可以用来控制多个线程之间的执行顺序。通过设置初始计数器,每个线程执行完后调用 countDown() 方法,主线程调用 await() 方法等待计数器归零,从而实现线程的顺序执行。

  2. 使用 Lock 和 Condition: 可以使用 ReentrantLockCondition 来实现线程的顺序执行。在每个线程中通过 Conditionawait()signal() 方法来控制线程的执行顺序。

import java.util.concurrent.CountDownLatch;

public class ThreadSequenceCountDownLatchExample {
    private static CountDownLatch latch1 = new CountDownLatch(1);
    private static CountDownLatch latch2 = new CountDownLatch(1);

    public static void main(String[] args) {
        Thread thread1 = new Thread(() -> {
            System.out.println("Thread 1 is running");
            latch1.countDown(); // 计数减一,释放等待在 latch1 上的线程
        });

        Thread thread2 = new Thread(() -> {
            try {
                latch1.await(); // 等待在 latch1 上
                System.out.println("Thread 2 is running");
                latch2.countDown(); // 计数减一,释放等待在 latch2 上的线程
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        Thread thread3 = new Thread(() -> {
            try {
                latch2.await(); // 等待在 latch2 上
                System.out.println("Thread 3 is running");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        thread1.start();
        thread2.start();
        thread3.start();
    }
}
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class ThreadSequenceConditionExample {
    private static ReentrantLock lock = new ReentrantLock();
    private static Condition condition1 = lock.newCondition();
    private static Condition condition2 = lock.newCondition();

    private static int turn = 1;

    public static void main(String[] args) {
        Thread thread1 = new Thread(() -> {
            lock.lock();
            try {
                while (turn != 1) {
                    condition1.await();
                }
                System.out.println("Thread 1 is running");
                turn = 2;
                condition2.signal();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        });

        Thread thread2 = new Thread(() -> {
            lock.lock();
            try {
                while (turn != 2) {
                    condition2.await();
                }
                System.out.println("Thread 2 is running");
                turn = 3;
                // 唤醒下一个线程
                condition1.signal();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        });

        Thread thread3 = new Thread(() -> {
            lock.lock();
            try {
                while (turn != 3) {
                    condition1.await();
                }
                System.out.println("Thread 3 is running");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        });

        thread1.start();
        thread2.start();
        thread3.start();
    }
}
  1. 使用线程池和 Future: 可以使用 ExecutorService 创建线程池,提交多个任务,并通过 Futureget() 方法获取线程的执行结果,从而实现线程的顺序执行。

  2. 使用 Semaphore: Semaphore 是另一个同步工具类,可以控制同时访问某个资源的线程个数。通过 Semaphore 的 acquire 和 release 方法,可以实现线程的顺序执行。

import java.util.concurrent.Semaphore;

public class ThreadSequenceSemaphoreExample {
    private static Semaphore semaphore1 = new Semaphore(1);
    private static Semaphore semaphore2 = new Semaphore(0);
    private static Semaphore semaphore3 = new Semaphore(0);

    public static void main(String[] args) {
        Thread thread1 = new Thread(() -> {
            try {
                semaphore1.acquire();
                System.out.println("Thread 1 is running");
                semaphore2.release();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        Thread thread2 = new Thread(() -> {
            try {
                semaphore2.acquire();
                System.out.println("Thread 2 is running");
                semaphore3.release();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        Thread thread3 = new Thread(() -> {
            try {
                semaphore3.acquire();
                System.out.println("Thread 3 is running");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        thread1.start();
        thread2.start();
        thread3.start();
        semaphore1.release(); // 启动第一个线程
    }
}

这些方法可以根据具体的需求和场景来选择合适的方式来实现多线程的顺序执行。在多线程编程中,确保线程按照指定的顺序执行可以避免竞态条件和数据不一致性等问题。