zoukankan      html  css  js  c++  java
  • java多线程与线程并发三:线程同步通信

    本文章内容整理自:张孝祥_Java多线程与并发库高级应用视频教程。

    有些时候,线程间需要传递消息,比如下面这道面试题:

    子线程循环10次,然后主线程循环100次,然后又回到子线程循环50次,然后再回到主线程循环100次。以上过程一共循环50次。

    通过分析可以知道,主线程和子线程是互斥的,即主线程和子线程不能同时执行。此外,主线程和子线程有固定的轮换关系,主线程执行完后,必须是子线程接着执行,然后又是主线程执行。

    要达到这种效果,光是线程互斥是不够的。因为有可能主线程执行完之后,cpu又将执行的权利分配给主线程,这样主线程又会执行一遍。要让两个线程交替执行,就需要这两个线程间可以通信。主线程执行完了,就通知子线程执行。子线程执行完了,再通知主线程执行。如此往复。

    像这种线程间协作的情况,就叫线程同步。

    下面直接贴出代码

    package com.sky.thread;
    
    public class Test4 {
        private boolean mainOrSub = true;//线程间通信的变量
        public static void main(String[] args) {
            final Test4 t4 = new Test4();
            new Thread(new Runnable() {
    
                @Override
                public void run() {
                    //执行50次主线程
                    for (int i = 0; i < 50; i++) {
                        try {
                            t4.mainThread();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }).start();
            new Thread(new Runnable() {
    
                @Override
                public void run() {
                    //执行50次子线程
                    for (int i = 0; i < 50; i++) {
                        try {
                            t4.subThread();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
    
                }
            }).start();
        }
    
        //主线程执行的方法
        public synchronized void mainThread() throws InterruptedException {
            //判断是否轮到自己执行
            //此处用while代替if,可以提高程序的健壮性。
            //线程有时会自己醒来,如果用if,当线程自己醒来后会接着执行this.wait()后面的代码,这样是不对的。
            //而使用while,线程自己醒来后,根据while的规则,会再判断一次mainOrSub的值。
            if (mainOrSub) {
                //如果mainOrSub是true,表示不该自己执行。于是把线程挂起。
                this.wait();
            }
            for (int i = 0; i < 100; i++) {
                System.out.println("main-"+Thread.currentThread().getName() + ":" + i);
            }
            //执行完毕后更改mainOrSub的状态,并唤醒其他线程
            mainOrSub = true;
            this.notify();
        }
    
        //子线程执行的方法
        public synchronized void subThread() throws InterruptedException {
            //判断是否轮到自己执行
            while (!mainOrSub) {
                //如果mainOrSub是false,表示不该自己执行。于是把线程挂起。
                this.wait();
            }
            for (int i = 0; i < 10; i++) {
                System.out.println("sub-"+Thread.currentThread().getName() + ":" + i);
            }
            //执行完毕后更改mainOrSub的状态,并唤醒其他线程
            mainOrSub = false;
            this.notify();
        }
    }

    在上面的代码中,创建了一个变量mainOrSub用于线程间通信。通过mainOrSub的值来控制线程的交替执行。

    可见,使用多个线程都可以访问到的变量,就可以实现线程间通信。 

    还有一点值得注意,在判断mainOrSub的值时,用while代替了if,这样可以提高程序的健壮性。因为使用wait()挂起的线程有时会自己醒来。如果用if,当线程自己醒来后会接着执行this.wait()后面的代码,而此时并不该它执行。如果用while,线程自己醒来后,根据while的规则,会再判断一次mainOrSub的值,这样就可以保证线程完全依照mainOrSub的值来决定要不要执行。

    经验:要用到共同数据(包括同步锁)的若干个方法应该归在同一个类身上,这种设计体现了高内聚和程序的健壮性。

  • 相关阅读:
    nginx反向代理下没有获取到正确的clientIP问题发散
    TPL概要
    OAuth2:Authorization Flows
    ArrayList部分源码解析
    二分法之通用模板
    Leetcodet题目解析-1 c++版
    git初始用+将git项目上传到github
    参加ACM省赛有感
    杭电acm 1274展开字符串
    杭电acm 1263水果
  • 原文地址:https://www.cnblogs.com/bailiyi/p/3622109.html
Copyright © 2011-2022 走看看