zoukankan      html  css  js  c++  java
  • 多线程(生产者和消费者模式)

    多线程的理解分析:

    生产者和消费者多线程体现(线程间通信问题)以学生作为资源来实现的
            生产者Producer 生产某个对象(共享资源),放在缓冲池中,然后消费者从缓冲池中取出这个对象。也就是生产者生产一个,消费者取出一个。这样进行循环
            资源类:Student
            设置数据类:SetThread(生产者)
            获取数据类:GetThread(消费者)
            测试类:StudentDemo
            

    1. 资源类 Student

    package FF;
    
    public class Student {
        private String name;
        private int age;
        private boolean flag; // 默认情况是没有数据,如果是true,说明有数据
    
        public synchronized void set(String name, int age) {
            // 如果有数据,就等待
            if (this.flag) {
                try {
                    this.wait();//等待,释放锁
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
    
            // 设置数据
            this.name = name;
            this.age = age;
    
            // 修改标记
            this.flag = true;
            this.notify();
        }
    
        public synchronized void get() {
            // 如果没有数据,就等待
            if (!this.flag) {
                try {
                    this.wait();//等待,释放锁
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
    
            // 获取数据
            System.out.println(this.name + "---" + this.age);
    
            // 修改标记
            this.flag = false;
            this.notify();
        }
    }

    2. 设置数据类:SetThread(生产者)


      

    package FF;
    
    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) {
                if (x % 2 == 0) {
                    s.set("林青霞", 27);
                } else {
                    s.set("刘意", 30);
                }
                x++;
            }
        }
    }

    3.GetThread(消费者)

    package FF;
    
    public class GetThread implements Runnable {
        private Student s;
    
        public GetThread(Student s) {
            this.s = s;
        }
    
        @Override
        public void run() {
            while (true) {
                s.get();
            }
        }
    }

    4.测试类:StudentDemo

    package FF;
    
    /*
     * 分析:
     *         资源类:Student    
     *         设置学生数据:SetThread(生产者)
     *         获取学生数据:GetThread(消费者)
     *         测试类:StudentDemo
     * 
     * 问题1:按照思路写代码,发现数据每次都是:null---0
     * 原因:我们在每个线程中都创建了新的资源,而我们要求的时候设置和获取线程的资源应该是同一个
     * 如何实现呢?
     *         在外界把这个数据创建出来,通过构造方法传递给其他的类。
     * 
     * 问题2:为了数据的效果好一些,我加入了循环和判断,给出不同的值,这个时候产生了新的问题
     *         A:同一个数据出现多次
     *         B:姓名和年龄不匹配
     * 原因:
     *         A:同一个数据出现多次
     *             CPU的一点点时间片的执行权,就足够你执行很多次。
     *         B:姓名和年龄不匹配
     *             线程运行的随机性
     * 线程安全问题:
     *         A:是否是多线程环境        是
     *         B:是否有共享数据        是
     *         C:是否有多条语句操作共享数据    是
     * 解决方案:
     *         加锁。
     *         注意:
     *             A:不同种类的线程都要加锁。
     *             B:不同种类的线程加的锁必须是同一把。
     * 
     * 问题3:虽然数据安全了,但是呢,一次一大片不好看,我就想依次的一次一个输出。
     * 如何实现呢?
     *         通过Java提供的等待唤醒机制解决。
     * 
     * 等待唤醒:
     *         Object类中提供了三个方法:
     *             wait():等待,释放锁
     *             notify():唤醒单个线程
     *             notifyAll():唤醒所有线程
     *         为什么这些方法不定义在Thread类中呢?
     *             这些方法的调用必须通过锁对象调用,而我们刚才使用的锁对象是任意锁对象。
     *             所以,这些方法必须定义在Object类中。
     * 
     * 最终版代码中:
     *         把Student的成员变量给私有的了。
     *         把设置和获取的操作给封装成了功能,并加了同步。
     *         设置或者获取的线程里面只需要调用方法即可。
     */
    public class StudentDemo {
        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();
        }
    }


             

  • 相关阅读:
    Delphi 实现C语言函数调用
    Delphi采用接口实现DLL调用
    select、poll、epoll之间的区别总结[整理]
    int 的重载
    qt 安装包生成2
    线程池的简单实现
    qt 安装包生成
    linux 下tftpf搭建
    2018C语言助教总结
    动态规划——最长子序列长度
  • 原文地址:https://www.cnblogs.com/x-ll123/p/9231215.html
Copyright © 2011-2022 走看看