多线程之间是抢占资源的,使用线程通信可以达到线程按序执行的目的 线程共享资源类, 首先创建一个资源类, 包含三个打印的方法以及首次打印的字符串
多个线程访问,方法加synchronized同步锁
- class Resource {
- String currentPrint = "AA"; // 初始打印,打印之后赋值为下一个要打印的内容
- /**
- * 打印AA
- * [url=home.php?mod=space&uid=3142012]@param[/url] next 下一个要打印的字符串
- * @throws InterruptedException
- */
- public synchronized void printAA(String next) throws InterruptedException {
- // 不是要打印的内容, 阻塞线程
- while (!Objects.equals(currentPrint, "AA")) {
- wait();
- }
- for (int i = 0; i < 3; i++) {
- System.out.println(Thread.currentThread().getName() + ": AA");
- }
- currentPrint= next;
- // 随机唤醒一个线程
- notify();
- }
- /**
- * 打印BB
- * @param next 下一个要打印的字符串
- * @throws InterruptedException
- */
- public synchronized void printBB(String next) throws InterruptedException {
- // 不是要打印的内容, 阻塞线程
- while (!Objects.equals(currentPrint, "BB")) {
- wait();
- }
- for (int i = 0; i < 3; i++) {
- System.out.println(Thread.currentThread().getName() + ": BB");
- }
- currentPrint= next;
- // 随机唤醒一个线程
- notify();
- }
- /**
- * 打印CC
- * @throws InterruptedException
- */
- public synchronized void printCC() throws InterruptedException {
- // 不是要打印的内容, 阻塞线程
- while (!Objects.equals(currentPrint, "CC")) {
- wait();
- }
- for (int i = 0; i < 3; i++) {
- System.out.println(Thread.currentThread().getName() + ": CC");
- }
- }
- }
复制代码
创建线程执行程序进行交替打印
- public class AABBCC {
- public static void main(String[] args) {
- ThreadPoolExecutor threadPoolExecutor = null;
- try {
- // 创建一个最大长度为3的线程池
- threadPoolExecutor = new ThreadPoolExecutor(3, 3, 0,
- TimeUnit.SECONDS, new LinkedBlockingDeque(10), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
- Resource resource = new Resource();
- // 将要执行的任务插入到集合中
- List list = new ArrayList<>();
- list.add(()->{try { resource.printAA("BB"); } catch (InterruptedException e) { e.printStackTrace(); }});
- list.add(()->{try { resource.printBB("CC"); } catch (InterruptedException e) { e.printStackTrace(); }});
- list.add(()->{try { resource.printCC();} catch (InterruptedException e) {e.printStackTrace();}});
- for (int i = 0; i < list.size(); i++) {
- threadPoolExecutor.execute(list.get(i));
- }
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- // 关闭线程池
- if (threadPoolExecutor != null) {
- threadPoolExecutor.shutdown();
- }
- }
- }
- }
复制代码
执行结果
资源类冗余代码进行优化
- /**
- * 打印字符串
- * @param currentPrintParam 当前
- * @param next 下一个
- * @param times 打印次数
- * @throws InterruptedException
- */
- public synchronized void printStr(String currentPrintParam,String next, int times) throws InterruptedException {
- // 不是要打印的内容, 阻塞线程
- while (!Objects.equals(currentPrint, currentPrintParam)) {
- wait();
- }
- for (int i = 0; i < times; i++) {
- System.out.println(Thread.currentThread().getName() + ": "+ currentPrint);
- }
- currentPrint = next;
- // 随机唤醒一个线程
- notify();
- }
复制代码
调用方法替换
- Resource resource = new Resource();
- // 将要执行的任务插入到集合中
- List list = new ArrayList<>();
- list.add(()->{try { resource.printStr("AA", "BB", 3); } catch (InterruptedException e) { e.printStackTrace(); }});
- list.add(()->{try { resource.printStr("BB", "CC", 3); } catch (InterruptedException e) { e.printStackTrace(); }});
- list.add(()->{try { resource.printStr("CC", "", 3);} catch (InterruptedException e) {e.printStackTrace();}});
- for (int i = 0; i < list.size(); i++) {
- threadPoolExecutor.execute(list.get(i));
- }
复制代码
执行结果
JDK5在java.util.concurrent包下提供了Lock并发锁
资源类代码新增
- Lock lock = new ReentrantLock(); // 并发锁
- Condition aCondition = lock.newCondition();
- Condition bCondition = lock.newCondition();
- Condition cCondition = lock.newCondition();
- /**
- * 打印字符串
- * @param currentPrintParam 当前线程打印
- * @param nextPrint 下一个线程打印
- * @param currentCondition 当前线程
- * @param nextCondition 下一个线程
- * @param times 打印次数
- * @throws InterruptedException
- */
- public void lockPrintStr(String currentPrintParam, String nextPrint, Condition currentCondition, Condition nextCondition, int times) {
- lock.lock();
- try {
- // 不是要打印的内容 阻塞线程
- while (!Objects.equals(currentPrint, currentPrintParam)) {
- currentCondition.await();
- }
- for (int i = 0; i < times; i++) {
- System.out.println(Thread.currentThread().getName() + ": "+ currentPrint);
- }
- currentPrint = nextPrint;
- // 唤醒下一个线程
- if (!Objects.isNull(nextCondition)) {
- nextCondition.signal();
- }
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- // 释放锁
- if (lock != null) {
- lock.unlock();
- }
- }
- }
复制代码
调用新增的方法
- Resource resource = new Resource();
- // 将要执行的任务插入到集合中
- List list = new ArrayList<>();
- list.add(()->{resource.lockPrintStr("AA", "BB", resource.aCondition, resource.bCondition, 3);});
- list.add(()->{resource.lockPrintStr("BB", "CC", resource.bCondition, resource.cCondition, 3);});
- list.add(()->{resource.lockPrintStr("CC", "", resource.cCondition, null, 3);});
- for (int i = 0; i < list.size(); i++) {
- threadPoolExecutor.execute(list.get(i));
- }
复制代码
多次执行的结果中可以看出,由三个线程交替打印AABBCC
总结:
线程通信其中两种方式 Object类下wait()、notify()/notifyAll(),以及JDK5以后提供的Lock下Condition内部类的await()、signal()方法。
使用wait/notify进行线程通信只能够随机唤醒,增加了上下文的切换时间,使用await/signal可以实现精准唤醒,java集合框架中的队列就采用了后者实现线程通信
|