• 【线程间通信:代码示例:分析问题原因:修正代码】


    针对同一个资源的操作有不同种类的线程:生产线程和消费线程

    package com.test;
    
    public class Student {
    
        String name;
        int age;
    
    }
    package com.test;
    
    public class SetThread implements Runnable {
    
        private Student s;
    
        public SetThread(Student s){
            this.s = s;
        }
        @Override
        public void run() {
            s.name="叶胖子";
            s.age=27;
        }
    
    }
    package com.test;
    
    public class GetThread implements Runnable {
    
        private Student s;
    
        public GetThread(Student s){
            this.s = s;
        }
    
        @Override
        public void run() {
            System.out.println(s.name+"---"+s.age);
        }
    }
    package com.test;
    
    public class StudentTest {
    
        public static void main(String[] args) {
    
            Student s = new Student();
    
            SetThread st = new SetThread(s);
            GetThread gt = new GetThread(s);
    
            Thread t1 = new Thread(st);
            Thread t2 = new Thread(gt);
    
            t1.start();
            t2.start();
    
        }
    
    }

    执行结果:

    null---0

    分析:

      资源类:Student

      设置学生数据:SetThread(生产者)

      获取学生数据:GetThread(消费者)

      测试类:StudentTest

    问题一:执行测试类,发现输出结果是null---0

      原因:我们在每个线程中都创建了新的资源,而我们要求的是设置和获取的资源应该是同一个学生对象。

      解决办法:在外界把这个对象创建出来,通过构造方法传递给生产者和消费者。

    问题二:为了数据的效果好一些,我如果加入了循环和判断,给出不同的值,这时会出现新的问题

      A:同一个数据出现多次

      B:姓名和年龄不匹配

      原因:A:同一个数据出现多次,CPU的一点点时间片的执行权,就足够你执行很多次。

         B:姓名和年龄不匹配,是因为线程运行的随机性。

      线程安全问题:

        A:是否是多线程环境(是)

        B:是否有共享数据(是)

        C:是否有多条语句操作共享数据(是)

      解决方案:加锁

      注意:A:不同种类的线程都要加锁

            B:不同种类的线程加的锁必须是同一把

    实现线程安全后的代码如下:

    package com.test;
    
    public class Student {
    
        String name;
        int age;
    
    }
    package com.test;
    
    public class SetThread implements Runnable {
    
        private Student s;
        private int x = 0;
    
        public SetThread(Student s){
            this.s = s;
        }
        @Override
        public void run() {
            while(true){
                synchronized (s){
                    if(x%2==0){
                        s.name="叶胖子";
                        s.age=30;
                    }else{
                        s.name="王瘦子";
                        s.age=31;
                    }
                    x++;
                }
            }
        }
    
    }
    package com.test;
    
    public class GetThread implements Runnable {
    
        private Student s;
    
        public GetThread(Student s){
            this.s = s;
        }
    
        @Override
        public void run() {
            while (true){
                synchronized(s){
                    System.out.println(s.name+"---"+s.age);
                }
            }
        }
    
    }
    package com.test;
    
    public class StudentTest {
    
        public static void main(String[] args) {
    
            Student s = new Student();
    
            SetThread st = new SetThread(s);
            GetThread gt = new GetThread(s);
    
            Thread t1 = new Thread(st);
            Thread t2 = new Thread(gt);
    
            t1.start();
            t2.start();
    
        }
    
    }
    终身学习者
  • 相关阅读:
    使用Apworks开发基于CQRS架构的应用程序(六):创建.NET WCF服务
    Microsoft NLayerApp案例理论与实践 项目简介与环境搭建
    使用Apworks开发基于CQRS架构的应用程序(七):配置数据库
    测试一下亚马逊联盟
    Revit参数族之DMD系列静电水处理器
    Revit参数族之ZP系列消声器
    第一个Ruby程序:Hello world!
    百度文库下载器冰点下载
    sketchup ruby编程之绘制梯段
    加西亚马尔克斯枯枝败叶
  • 原文地址:https://www.cnblogs.com/zuixinxian/p/9572382.html
Copyright © 2020-2023  润新知