1. 程式人生 > >java多線程通信

java多線程通信

同步代碼塊 自己 working 創建 dna 一個 post ++ latch

最近在研究java多線程,這篇文章主要是介紹一些線程之間的通信:

1:join 的方式,一個線程等待另一個線程執行完畢後在執行,可以控制線程執行的順序;

場景:B線程要在A線程完成後才開始任務:

不做任何控制的情況下的線程代碼如下:

@Test
    public void threadTest4() throws InterruptedException, ExecutionException {
//        線程A
        final Thread threadA = new Thread(new Runnable() {
            @Override
            
public void run() { printNum("線程A"); } }); // 線程B Thread threadB= new Thread(new Runnable() { @Override public void run() { // try { // threadA.join(); // } catch (InterruptedException e) {
// e.printStackTrace(); // } printNum("線程B"); } }); threadA.start(); threadB.start(); Thread.sleep(1000); }
private void printNum(String threadName){
        int i=0;
        while (i++<3){
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(threadName+"打印"+i);
        }
    }

這樣打印出來的效果如下:

線程B打印1
線程A打印1
線程B打印2
線程A打印2
線程B打印3
線程A打印3

這樣不能保證 B 線程在A 線程執行完之後再執行;可以通過 join 方法來實現我們的需求: 當在 B 線程調用 A線程的join 方法 則會 B 線程等待A線程執行完了之後再執行B 線程;將上面註掉的代碼解開就行了;

這樣打印出來的效果是:

線程A打印1
線程A打印2
線程A打印3
線程B打印1
線程B打印2
線程B打印3

這樣就能保證 B 線程在 A線程執行結束後再執行;

2:多個線程按照一定的順序交叉執行:

場景:A 線程執行打印完 1 2 後 B 線程再執行打印 1 2 3

這樣的場景需要使用 鎖的等待和喚醒的機制來實現,代碼實現如下: 需要用到兩個方法 wait 和 notify 方法 這兩個方法都是 Object對象的方法;

@Test
    public void threadTest5() throws InterruptedException, ExecutionException {
        final Object o=new Object();
        Thread threadA = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (o){
                    System.out.println("線程A 打印 1");
                    try {
                        o.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("線程A 打印 2");
                    System.out.println("線程A 打印 3");
                }

            }
        });

        Thread threadB = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (o){
                    System.out.println("線程B 打印 1");
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("線程B 打印 2");
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("線程B 打印 3");
                    o.notify();
                }

            }
        });
        threadA.start();
        threadB.start();
        Thread.sleep(1000);
    }

下面分析這段代碼的執行順序:

1:創建對象鎖

final Object o=new Object();

2:A 首先獲得對象鎖的控制權;

3:A 調用 wait 方法 讓出對象鎖的控制權:

o.wait();

4:B 線程獲得對象鎖的控制權:

B線程的業務代碼處理完之後 調用 notify 方法,喚醒 正在 wait 的線程 然後結束B線程的同步代碼塊,

5:A 線程獲取到了對象鎖的控制權後執行自己的業務邏輯;

這樣就滿足我們需要的場景;

3: 四個線程 A B C D,其中 D 要等到 A B C 全執行完畢後才執行,而且 A B C 是同步運行的

通過 調用對象鎖的 notify 和 wait 方法可以滿足線程的執行順序 但是線程是一次執行的,不能同時進行;

需要同步進行有需要進行控制線程的執行順序則可以使用 線程計數器來實現

代碼如下:

@Test
    public void threadTest1() throws InterruptedException {
        int worker = 3;
        System.out.println("計數器的值為:" + worker);
        final CountDownLatch countDownLatch = new CountDownLatch(worker);
        Thread threadD = new Thread(new Runnable() {
            @Override
            public void run() {

                System.out.println("D 線程等待其他線程!");
                try {
                    countDownLatch.await();
                    System.out.println("其他線程運行結束,D線程開始");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        threadD.start();

        for (int i = 0; i < 3; i++) {

            final int finalI = i;
            Thread threadA = new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName() + finalI + "is working");
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + finalI + "is finish");
                    countDownLatch.countDown();
                }
            });
            threadA.start();
        }

        Thread.sleep(1000);

    }

  上面代碼的執行順序如下:

1:創建線程計數器:計數器的計數個數為3;

2:當D線程開始執行的時候調用計數器的 await 方法,然後等待;

3:執行 ABC 線程的業務邏輯的處理,在線程的業務邏輯處理之後分別調用 計數器的 數字減1.

4:當計數器的數值為0 時D線程獲得執行權,開始執行;

4:多線程獲取線程處理的返回值:

代碼如下:

@Test
    public void threadTest3() throws InterruptedException, ExecutionException {
        Callable<Integer> callable = new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                System.out.println("開始任務!!");
                Thread.sleep(100);
                int result=0;
                for (int i = 0; i <100 ; i++) {
                    result +=i;
                }
                return result;
            }
        };
        FutureTask<Integer> futureTask = new FutureTask<Integer>(callable);
        new Thread(futureTask).start();
        System.out.println("任務獲取前");
        System.out.println("任務獲取到的結果是:"+futureTask.get());
        System.out.println("任務獲取後");
        Thread.sleep(1000);

    }

通過Callable 和 FutureTask 兩類可以實現這個功能, 註意 FutureTask 的 get()方法是同步,必須在callable中的call 方法執行結束後;



java多線程通信