1. 程式人生 > 其它 >java 多執行緒按順序執行、順序獲取結果

java 多執行緒按順序執行、順序獲取結果

技術標籤:Android面試多執行緒java順序面試

文章目錄

1、通過Thread的join方法

join主要是讓父執行緒等待子執行緒結束之後父執行緒才能繼續執行

    public static void main(String[] args) throws InterruptedException {
        System.out.println("---開啟執行緒1---");
        MyThread t1 = new MyThread("執行緒1");
        t1.start();
        t1.join();

        System.out.println("---開啟執行緒2---");
        MyThread t2 = new MyThread("執行緒2");
        t2.start();
        t2.join();

        System.out.println("---開啟執行緒3---");
        MyThread t3 = new MyThread("執行緒3");
        t3.start();
        t3.join();
        
    }
    
    static class MyThread extends Thread {
        public MyThread(String name){
            super(name);
        }
        @Override
        public void run() {
            super.run();
            System.out.println(Thread.currentThread().getName()+"執行了");
        }
    }

列印結果

---開啟執行緒1---
執行緒1執行了
---開啟執行緒2---
執行緒2執行了
---開啟執行緒3---
執行緒3執行了

2、FutureTask

   public static void main(String[] args) throws InterruptedException, ExecutionException {
        System.out.println("---開啟執行緒1---");
        FutureTask<String> f1 = new FutureTask<>(new MyCall());
        Thread t1 = new Thread(f1,"執行緒1");
        t1.start();
        System.out.println("執行緒1返回結果: " + f1.get());

        System.out.println("---開啟執行緒2---");
        FutureTask<String> f2 = new FutureTask<>(new MyCall());
        Thread t2 = new Thread(f2,"執行緒2");
        t2.start();
        System.out.println("執行緒2返回結果: " + f2.get());

        System.out.println("---開啟執行緒3---");
        FutureTask<String> f3 = new FutureTask<>(new MyCall());
        Thread t3 = new Thread(f3,"執行緒3");
        t3.start();
        System.out.println("執行緒3返回結果: " + f3.get());
    }
    
    
    static class MyCall implements Callable<String> {
        @Override
        public String call() throws Exception {
            return Thread.currentThread().getName();
        }
    }

列印結果

---開啟執行緒1---
執行緒1返回結果: 執行緒1
---開啟執行緒2---
執行緒2返回結果: 執行緒2
---開啟執行緒3---
執行緒3返回結果: 執行緒3

3、CountDownLatch(倒計數)

現在有如下3個執行緒

   public static void main(String[] args) throws InterruptedException, ExecutionException {

        System.out.println("---開啟執行緒1---");
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(500);
                    System.out.println("執行緒1執行了。。。");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        }, "執行緒1");
        t1.start();

        System.out.println("---開啟執行緒2---");
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(200);
                    System.out.println("執行緒2執行了。。。");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        }, "執行緒2");
        t2.start();

        System.out.println("---開啟執行緒3---");
        Thread t3 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(100);
                    System.out.println("執行緒3執行了。。。");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "執行緒3");
        t3.start();
    }

它們的執行結果是

---開啟執行緒1---
---開啟執行緒2---
---開啟執行緒3---
執行緒3執行了。。。
執行緒2執行了。。。
執行緒1執行了。。。

上面的輸出是按照3、2、1輸出的。如果現在要按照1、2、3的順序進行輸出,每個執行緒的sleep時間不能修改,該如何去處理?可以藉助CountDownLatch

    private static CountDownLatch c1 = new CountDownLatch(1);
    private static CountDownLatch c2 = new CountDownLatch(1);
    public static void main(String[] args) throws InterruptedException, ExecutionException {

        System.out.println("---開啟執行緒1---");
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(500);
                    System.out.println("執行緒1執行了。。。");
                    c1.countDown();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        }, "執行緒1");
        t1.start();

        System.out.println("---開啟執行緒2---");
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    c1.await();
                    Thread.sleep(200);
                    System.out.println("執行緒2執行了。。。");
                    c2.countDown();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        }, "執行緒2");
        t2.start();

        System.out.println("---開啟執行緒3---");
        Thread t3 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    c2.await();
                    Thread.sleep(100);
                    System.out.println("執行緒3執行了。。。");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "執行緒3");
        t3.start();
    }

它們的執行結果是

---開啟執行緒1---
---開啟執行緒2---
---開啟執行緒3---
執行緒1執行了。。。
執行緒2執行了。。。
執行緒3執行了。。。

4、wait、notify

    private final static Object lock1 = new Object();
    private final static Object lock2 = new Object();
    
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        System.out.println("---開啟執行緒1---");
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (lock1) {
                    try {
                        lock1.wait();
                        Thread.sleep(500);
                        System.out.println("執行緒1執行了。。。");
                        lock1.notify();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }, "執行緒1");
        t1.start();
        Thread.sleep(10);//這個主要保證執行緒開啟的順序
        
        System.out.println("---開啟執行緒2---");
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (lock1) {
                    try {
                        lock1.notify();
                        lock1.wait();
                        Thread.sleep(200);
                        System.out.println("執行緒2執行了。。。");
                        synchronized (lock2) {
                            lock2.notify();
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

            }
        }, "執行緒2");
        t2.start();
        Thread.sleep(10);
        
        System.out.println("---開啟執行緒3---");
        Thread t3 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (lock2) {
                    try {
                        lock2.wait();
                        Thread.sleep(100);
                        System.out.println("執行緒3執行了。。。");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }, "執行緒3");
        t3.start();

    }

列印結果

---開啟執行緒1---
---開啟執行緒2---
---開啟執行緒3---
執行緒1執行了。。。
執行緒2執行了。。。
執行緒3執行了。。。

5、Condition(條件變數)

    private static Lock lock = new ReentrantLock();
    private static Condition condition1 = lock.newCondition();
    private static Condition condition2 = lock.newCondition();

    public static void main(String[] args) throws InterruptedException, ExecutionException {
        System.out.println("---開啟執行緒1---");
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    lock.lock();
                    condition1.await();
                    Thread.sleep(500);
                    System.out.println("執行緒1執行了。。。");
                    condition1.signal();
                    lock.unlock();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "執行緒1");
        t1.start();

        System.out.println("---開啟執行緒2---");
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    lock.lock();
                    condition1.signal();
                    condition1.await();
                    Thread.sleep(200);
                    System.out.println("執行緒2執行了。。。");
                    condition2.signal();
                    lock.unlock();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "執行緒2");
        t2.start();

        System.out.println("---開啟執行緒3---");
        Thread t3 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    lock.lock();
                    condition2.await();
                    Thread.sleep(100);
                    System.out.println("執行緒3執行了。。。");
                    lock.unlock();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "執行緒3");
        t3.start();
    }

列印結果

---開啟執行緒1---
---開啟執行緒2---
---開啟執行緒3---
執行緒1執行了。。。
執行緒2執行了。。。
執行緒3執行了。。。

6、CyclicBarrier(迴環柵欄)

    private static CyclicBarrier barrier1 = new CyclicBarrier(2);
    private static CyclicBarrier barrier2 = new CyclicBarrier(2);

    public static void main(String[] args) throws InterruptedException, ExecutionException {
        System.out.println("---開啟執行緒1---");
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(500);
                    System.out.println("執行緒1執行了。。。");
                    barrier1.await();
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }
        }, "執行緒1");
        t1.start();

        System.out.println("---開啟執行緒2---");
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    barrier1.await();
                    Thread.sleep(200);
                    System.out.println("執行緒2執行了。。。");
                    barrier2.await();
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }
        }, "執行緒2");
        t2.start();

        System.out.println("---開啟執行緒3---");
        Thread t3 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    barrier2.await();
                    Thread.sleep(100);
                    System.out.println("執行緒3執行了。。。");
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }
        }, "執行緒3");
        t3.start();
    }

列印結果

---開啟執行緒1---
---開啟執行緒2---
---開啟執行緒3---
執行緒1執行了。。。
執行緒2執行了。。。
執行緒3執行了。。。

5、執行緒池

5.1、單執行緒化執行緒池

    private static ExecutorService executorService = Executors.newSingleThreadExecutor();

    public static void main(String[] args) throws InterruptedException, ExecutionException {
        System.out.println("---開啟執行緒1---");
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(500);
                    System.out.println("執行緒1執行了。。。");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "執行緒1");


        System.out.println("---開啟執行緒2---");
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(200);
                    System.out.println("執行緒2執行了。。。");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "執行緒2");


        System.out.println("---開啟執行緒3---");
        Thread t3 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(100);
                    System.out.println("執行緒3執行了。。。");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "執行緒3");
        executorService.submit(t1);
        executorService.submit(t2);
        executorService.submit(t3);
    }

列印結果

---開啟執行緒1---
---開啟執行緒2---
---開啟執行緒3---
執行緒1執行了。。。
執行緒2執行了。。。
執行緒3執行了。。。

5.2、多執行緒化執行緒池

其實最常見的還是使用多執行緒化的執行緒池去實現。

    private static ExecutorService executorService = Executors.newFixedThreadPool(3);
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        long start = System.currentTimeMillis();
        ArrayList<Future<String>> futureList = new ArrayList<Future<String>>();
        ArrayList<String> names = new ArrayList<String>();
        for (int i = 0; i < 3; i++) {
            futureList.add(executorService.submit(new MyCall(i + "")));
        }

        for (int i = 0; i < 3; i++) {
            Future<String> future = futureList.get(i);
            String value = future.get();
            System.out.println("執行緒"+value+"執行了");
        }
        long spendTime = System.currentTimeMillis() - start;
        System.out.println("花費時間---"+spendTime);

    }
    
    
    static class MyCall implements Callable<String> {
        private String name;

        public MyCall(String name) {
            this.name = name;
        }

        @Override
        public String call() throws Exception {
            switch (name){
                case "0":
                    Thread.sleep(3000);
                    break;
                case "1":
                    Thread.sleep(2000);
                    break;
                case "2":
                    Thread.sleep(1000);
                    break;
            }

            return name;
        }
    }

列印結果

執行緒0執行了
執行緒1執行了
執行緒2執行了
花費時間---3006

常見的問題:

  • 1、2、3總共3個執行緒,按順序請求,按順序取結果。
  • 1、2、3總共3個執行緒,執行緒3要等到執行緒1和2執行完才能執行,執行緒1和2是並行的。
  • 寫一個多執行緒程式,交替輸出1,2,1,2,1,2

相信上面的問題應該不難了。。

在這裡插入圖片描述