在Java中线程间通讯有多种方式,我这里列出一些常用方式,并用代码的方式展示他们是如何实现的:

  • 共享变量
  • wait, notify,notifyAll(这3个方法是Object对象中的方法,且必须与synchronized关键字结合使用)
  • CyclicBarrier、CountDownLatch
  • 利用LockSupport
  • Lock/Condition机制
  • 管道,创建管道输出流PipedOutputStream和管道输入流PipedInputStream

示例一:

package com.zhi.test;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;

import org.junit.Test;

/**
 * Java多线程-线程通讯示例<br>
 * flag作为共享变量JobB执行,notify通知Job执行,CountDownLatch通知主线程执行
 * 
 * @author 张远志
 * @since 2020年5月4日21:51:24
 *
 */
public class ThreadTest2 {
    private CountDownLatch latch;
    private volatile boolean flag = true;
    private Object lock = new Object();
    private AtomicInteger num = new AtomicInteger(0);

    class JobA implements Runnable {
        @Override
        public void run() {
            synchronized (lock) {
                flag = false;
                if (num.get() != 3) {
                    try {
                        lock.wait(); // wait方法会释放锁
                    } catch (InterruptedException e) {
                    }
                }
                System.out.println("任务A收到通知,继续执行作业");
            }
            latch.countDown();
        }
    }

    class JobB implements Runnable {
        @Override
        public void run() {
            while (flag) { // 保证JobA先申请到锁

            }
            synchronized (lock) {
                for (int i = 1; i <= 5; i++) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                    }
                    int a = num.incrementAndGet();
                    System.out.println("任务B第" + i + "次执行,num值为:" + a);
                    if (a == 3) {
                        lock.notify(); // 唤醒JobB线程,notify方法不会释放锁
                    }
                }
            }
            latch.countDown();
        }
    }

    @Test
    public void test() {
        latch = new CountDownLatch(2);
        new Thread(new JobA()).start();
        new Thread(new JobB()).start();
        try {
            latch.await(); // 保证2个线程都执行完毕
        } catch (InterruptedException e) {
        }
    }
}

  结果输出:

任务B第1次执行,num值为:1
任务B第2次执行,num值为:2
任务B第3次执行,num值为:3
任务B第4次执行,num值为:4
任务B第5次执行,num值为:5
任务A收到通知,继续执行作业

示例二:

package com.zhi.test;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.locks.LockSupport;

import org.junit.Test;

/**
 * Java多线程-线程通讯示例,利用LockSupport
 * 
 * @author 张远志
 * @since 2020年5月4日21:51:24
 *
 */
public class ThreadTest3 {
    private CountDownLatch latch;
    private volatile int num = 0;
    private Thread ta;
    private Thread tb;

    class JobA implements Runnable {
        @Override
        public void run() {
            if (num != 3) {
                LockSupport.park();
            }
            System.out.println("任务A收到通知,继续执行作业");
            latch.countDown();
        }
    }

    class JobB implements Runnable {
        @Override
        public void run() {
            for (int i = 1; i <= 5; i++) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                }
                num++;
                System.out.println("任务B第" + i + "次执行,num值为:" + num);
                if (num == 3) {
                    LockSupport.unpark(ta); // unpark会立即激活传入线程
                }
            }
            latch.countDown();
        }
    }

    @Test
    public void test() {
        latch = new CountDownLatch(2);
        ta = new Thread(new JobA());
        tb = new Thread(new JobB());
        ta.start();
        tb.start();
        try {
            latch.await(); // 保证2个线程都执行完毕
        } catch (InterruptedException e) {
        }
    }
}

 

posted on 2020-05-04 22:37  玄同太子  阅读(284)  评论(0编辑  收藏  举报