乐趣区

关于java:如何让多个线程顺序执行

先说一下为什么会有这样的要求,如果是简略的要求按程序执行代码,间接一行行写下来就行了。然而接口调用咱们个别都放在工作线程外面,而且有时候须要拿一个接口返回的参数去申请另一个接口,这就须要控制线程按某种程序执行。

办法 1:join()

public class A1 extends Thread {
    @Override
    public void run() {
        try {System.out.println("--- thread A1 start ---");
            sleep((long) (Math.random() * 30));
        } catch (InterruptedException e) {e.printStackTrace();
        }
        System.out.println("--- thread A1 end ---");
    }
}

public class A2 extends Thread {
    @Override
    public void run() {
        try {System.out.println("--- thread A2 start ---");
            sleep((long) (Math.random() * 30));
        } catch (InterruptedException e) {e.printStackTrace();
        }
        System.out.println("--- thread A2 end ---");
    }
}

public class A3 extends Thread {
    @Override
    public void run() {
        try {System.out.println("--- thread A3 start ---");
            sleep((long) (Math.random() * 30));
        } catch (InterruptedException e) {e.printStackTrace();
        }
        System.out.println("--- thread A3 end ---");
    }
}

public class OrderTest {public static void main(String[] args) {
        try {A1 a1 = new A1();
            a1.start();
            a1.join();
            A2 a2 = new A2();
            a2.start();
            a2.join();
            A3 a3 = new A3();
            a3.start();} catch (InterruptedException e) {e.printStackTrace();
        }
    }
}
// 控制台输入:--- thread A1 start ---
--- thread A1 end ---
--- thread A2 start ---
--- thread A2 end ---
--- thread A3 start ---
--- thread A3 end ---

a1.start()使 a1 进入就绪状态,a1和主线程都可能抢到 CPU 执行权,a1.join()使 a1 线程独占 CPU,主线程要等a1 执行完能力执行 a2 的初始化和 a2.start() 等后续代码。

另外,把 a2 的初始化和 a2.join() 放在 a3run()外面的第一行(即执行 a3 的逻辑代码前),把 a1 的初始化和 a1.join() 放在 a2run()外面的第一行,也能让 a1a2a3 程序执行,成果和上述代码雷同。

办法 2:wait() & notify()

public class B1 extends Thread{
    @Override
    public void run() {synchronized (this){
            try {System.out.println("--- thread B1 start ---");
                sleep((long) (Math.random() * 30));
                System.out.println("--- thread B1 end ---");
                notify();} catch (InterruptedException e) {e.printStackTrace();
            }
        }
    }
}

public class B2 extends Thread {
    @Override
    public void run() {B1 b1 = new B1();
        b1.start();
        synchronized (b1){
            try {b1.wait();
            } catch (InterruptedException e) {e.printStackTrace();
            }
        }
        synchronized (this){
            try {System.out.println("--- thread B2 start ---");
                sleep((long) (Math.random() * 30));
                System.out.println("--- thread B2 end ---");
                notify();} catch (InterruptedException e) {e.printStackTrace();
            }
        }
    }
}

public class B3 extends Thread {
    @Override
    public void run() {B2 b2 = new B2();
        b2.start();
        synchronized (b2){
            try {b2.wait();
                System.out.println("--- thread B3 start ---");
                sleep((long) (Math.random() * 30));
            } catch (InterruptedException e) {e.printStackTrace();
            }
            System.out.println("--- thread B3 end ---");
        }
    }
}

public class OrderTest {public static void main(String[] args) {new B3().start();}
}
// 控制台输入:--- thread B1 start ---
--- thread B1 end ---
--- thread B2 start ---
--- thread B2 end ---
--- thread B3 start ---
--- thread B3 end ---

须要留神的是,线程 B2 中调用 b1.wait() 的时候不是让 b1 对象期待,而是让获取到 b1 对象同步锁的以后线程期待。这外面的「以后线程」指的就是线程 B2 了。

线程 B1 中的 notify(),唤醒的是在以后对象上期待的线程(其实这里的notify() 相当于this.notiify())。

B2线程的 run() 外面,执行第一个 synchronized 代码块的时候,以后线程 wait 了,当被唤醒的时候继续执行后续代码(即第二个 synchronized 代码块);B3被唤醒后执行 b2.wait() 前面的代码:System.out.println("--- thread B3 start ---"); 等。

办法 3:线程池

public class OrderTest {public static void main(String[] args) {A1 a1 = new A1();
        A2 a2 = new A2();
        A3 a3 = new A3();
        ExecutorService single = Executors.newSingleThreadExecutor();
        single.submit(a1);
        single.submit(a2);
        single.submit(a3);
        single.shutdown();}
}
// 控制台输入:--- thread A1 start ---
--- thread A1 end ---
--- thread A2 start ---
--- thread A2 end ---
--- thread A3 start ---
--- thread A3 end ---

newSingleThreadExecutor只蕴含一个线程,而且能够保障线程按程序执行。

办法 4

最容易想到的方法,在一个线程的 run() 外面的结尾处初始化并启动另一个线程(thread.start()),这个简略就补贴代码了。

退出移动版