天天看點

java 多線程按順序執行、順序擷取結果1、通過Thread的join方法2、FutureTask3、CountDownLatch(倒計數)4、wait、notify5、Condition(條件變量)6、CyclicBarrier(回環栅欄)5、線程池

文章目錄

  • 1、通過Thread的join方法
  • 2、FutureTask
  • 3、CountDownLatch(倒計數)
  • 4、wait、notify
  • 5、Condition(條件變量)
  • 6、CyclicBarrier(回環栅欄)
  • 5、線程池
    • 5.1、單線程化線程池
    • 5.2、多線程化線程池

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

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

java 多線程按順序執行、順序擷取結果1、通過Thread的join方法2、FutureTask3、CountDownLatch(倒計數)4、wait、notify5、Condition(條件變量)6、CyclicBarrier(回環栅欄)5、線程池