zoukankan      html  css  js  c++  java
  • Java学习笔记46(多线程三:线程之间的通信)

    多个线程在处理同一个资源,但是线程的任务却不相同,通过一定的手段使各个线程能有效地利用资源,

    这种手段即:等待唤醒机制,又称作线程之间的通信

    涉及到的方法:wait(),notify()

    示例:

    两个线程一个输入,一个输出

    package demo;
    
    public class Resource {
        public String name;
        public String sex;
    }

    输入线程:

    package demo;
    
    public class Input implements Runnable {
        private Resource r = new Resource();
    
        public void run() {
            int i = 0;
            while (true) {
                if (i % 2 == 0) {
                    r.name = "张三";
                    r.sex = "男";
                } else {
                    r.name = "李四";
                    r.sex = "女";
                }
                i++;
            }
        }
    
    }

    输出线程:

    package demo;
    
    public class Output implements Runnable {
        private Resource r = new Resource();
        public void run(){
            while (true) {
                System.out.println(r.name+"..."+r.sex);
            }
        }
    }

    测试类:

    package demo;
    
    public class ThreadDemo {
        public static void main(String[] args) {
            Input in = new Input();
            Output out = new Output();
            Thread tin = new Thread(in);
            Thread tout = new Thread(out);
            
            tin.start();
            tout.start();
        }
    }

    运行后却发现输出的都是null...null

    因为输入线程和输出线程中创建的Resource对象使不同的

    解决null问题:

    package demo;
    
    public class Input implements Runnable {
        private Resource r;
        
        public Input(Resource r){
            this.r = r;
        }
    
        public void run() {
            int i = 0;
            while (true) {
                if (i % 2 == 0) {
                    r.name = "张三";
                    r.sex = "男";
                } else {
                    r.name = "李四";
                    r.sex = "女";
                }
                i++;
            }
        }
    
    }
    package demo;
    
    public class Output implements Runnable {
        private Resource r;
        
        public Output(Resource r){
            this.r = r;
        }
        
        public void run(){
            while (true) {
                System.out.println(r.name+"..."+r.sex);
            }
        }
    }
    package demo;
    
    public class ThreadDemo {
        public static void main(String[] args) {
            
            Resource r = new Resource();
            
            Input in = new Input(r);
            Output out = new Output(r);
            Thread tin = new Thread(in);
            Thread tout = new Thread(out);
            
            tin.start();
            tout.start();
        }
    }

    运行后又发现了另一个问题:

    输出中含有:张三...女或者李四...男,性别出错

    发生原因:

    赋值完张三和男后,继续赋值李四和女,这时候还未还得及赋值女,就进入了输出线程,这时候就会输出李四...男

    于是想到加上同步:

        public void run() {
            int i = 0;
            while (true) {
                synchronized (this) {
                    if (i % 2 == 0) {
                        r.name = "张三";
                        r.sex = "男";
                    } else {
                        r.name = "李四";
                        r.sex = "女";
                    }
                    i++;
                }
            }
        }
        public void run() {
            while (true) {
                synchronized (this) {
                    System.out.println(r.name + "..." + r.sex);
                }
            }
        }

    然而问题并没有解决:

    原因:

    这里的同步失去了作用,用到的不是一个锁

    解决办法:

    使用一个共同的锁即可

    public void run() {
            int i = 0;
            while (true) {
                synchronized (r) {
                    if (i % 2 == 0) {
                        r.name = "张三";
                        r.sex = "男";
                    } else {
                        r.name = "李四";
                        r.sex = "女";
                    }
                    i++;
                }
            }
        }
        public void run() {
            while (true) {
                synchronized (r) {
                    System.out.println(r.name + "..." + r.sex);
                }
            }
        }

    这时候就是正常的输出了

     但是还是存在一个问题,我们希望的是张三和李四交错出现,一个张三一个李四,现在依然是随机出现的,大片的张三或李四

    解决办法:

    先让input线程赋值,然后让output线程输出,并且让输入线程等待,不允许再赋值李四,等待输出张三结束后,再允许李四赋值,依次下去

    输入线程也需要同样的方式,输出完后要等待

    这时候就需要用到等待唤醒机制:

    输入:赋值后,执行方法wait()永远等待

    输出:打印后,再输出等待之前,唤醒输入notify(),自己再wait()永远等待

    输入:被唤醒后,重新赋值,必须notify()唤醒输出的线程,自己再wait()等待

    依次循环下去

    代码实现:

    package demo;
    
    public class Resource {
        public String name;
        public String sex;
        public boolean flag = false;
    }
    package demo;
    
    public class Input implements Runnable {
        private Resource r;
    
        public Input(Resource r) {
            this.r = r;
        }
    
        public void run() {
            int i = 0;
            while (true) {
                synchronized (r) {
                    if (r.flag) {
                        try {
                            r.wait();
                        } catch (Exception e) {
                        }
                    }
                    if (i % 2 == 0) {
                        r.name = "张三";
                        r.sex = "男";
                    } else {
                        r.name = "李四";
                        r.sex = "女";
                    }
                    r.flag = true;
                    r.notify();
                }
                i++;
            }
        }
    }
    package demo;
    
    public class Output implements Runnable {
        private Resource r;
    
        public Output(Resource r) {
            this.r = r;
        }
    
        public void run() {
            while (true) {
                synchronized (r) {
                    if (!r.flag) {
                        try {
                            r.wait();
                        } catch (Exception e) {
                        }
                    }
                    System.out.println(r.name + "..." + r.sex);
                    r.flag = false;
                    r.notify();
                }
            }
        }
    }
    package demo;
    
    public class ThreadDemo {
        public static void main(String[] args) {
    
            Resource r = new Resource();
    
            Input in = new Input(r);
            Output out = new Output(r);
            Thread tin = new Thread(in);
            Thread tout = new Thread(out);
    
            tin.start();
            tout.start();
        }
    }

    这时候就是张三李四交错输出了

    完成

  • 相关阅读:
    软链接和硬链接
    Hive的基本常识
    Hadoop
    Docker技术
    人生苦短,我用Python(6)
    人生苦短,我用Python(5)
    人生苦短,我用Python(4)
    openssl telnet openssh
    iptables
    http与httpd
  • 原文地址:https://www.cnblogs.com/xuyiqing/p/8320488.html
Copyright © 2011-2022 走看看