JavaWeb实战篇:视图化了解多线程Wait、NotifyAll使用案例

qiaohhgz 2018-05-15 13:56:25 ⋅ 588 阅读

内容简介

本节针对于我们常听说而不常使用的 wait 和 notify 方法做个生产者和消费者案例

效果图

多线程

目录结构

目录结构

一、Task 负责封装任务

package com.itunion.model;/** * 任务 */public class Task {
    private String name;    public Task(String name) {        this.name = name;
    }   // 省略 get set}

任务对象主要负责数据参数的产地

二、Worker 负责消费任务

package com.itunion.model;import java.util.LinkedList;import java.util.Random;/** * 任务消费者 */public class Worker extends Thread {    private LinkedList<Task> tasks;    private Task task;    public Worker(String name, LinkedList<Task> tasks) {        super(name);        this.tasks = tasks;
    }    @Override
    public void run() {        try {            // 重复执行的任务
            while (true) {                // 对任务队列加锁
                synchronized (tasks) {                    // 如果没有任务就等待, 这里要用while 循环而不是 if 判断
                    while (tasks.isEmpty()) {                        // 等待任务
                        tasks.wait();
                    }                    // 获取任务
                    task = tasks.pop();                    // 反馈通知
                    tasks.notifyAll();
                }                // 执行任务 注意:执行任务不要放在同步块里面,那样的话任务队列会等到当前线程执行完之后才能拿到锁
                System.out.println(getName() + " 执行任务: " + task.getName());                // 模拟执行时间
                int workTime = new Random().nextInt(2000);
                Thread.sleep(workTime);                // 执行完毕
                System.out.println(getName() + " 执行任务: " + task.getName() + "完毕 用时:" + workTime);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }    public Task getTask() {        return task;
    }
}

三、Master 负责管理任务和消费者

package com.itunion.model;import java.util.LinkedList;/** * 生产者 * @author qiao * @version 2018/5/14 */public class Master extends Thread {    private LinkedList<Worker> workers = new LinkedList<>();    private LinkedList<Task> tasks = new LinkedList<>();    public Master(int count) {        super("生产者");        for (int i = 0; i < count; i++) {
            workers.add(new Worker("消费者 " + i, tasks));
        }        // 启动所有消费者
        for (Worker worker : workers) {
            worker.start();
        }
    }    /**     * 带阻塞的任务提交     * @param task     */
    public void submit(Task task) {        synchronized (tasks) {            while (tasks.size() == workers.size()) {                try {
                    tasks.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            tasks.add(task);
            tasks.notifyAll();
        }
    }    /**     * 提交任务     * @param task     */
    public void addTask(Task task) {        synchronized (tasks) {
            tasks.add(task);
            tasks.notifyAll();
        }
    }    /**     * 等待所有工作完毕     */
    public void waitWorks() {        synchronized (workers) {            boolean hasWork = false;            for (Worker worker : workers) {                if (worker.getState() == State.RUNNABLE) {
                    hasWork = true;                    break;
                }
            }            while (hasWork) {                try {
                    workers.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }    public LinkedList<Worker> getWorkers() {        return workers;
    }    public LinkedList<Task> getTasks() {        return tasks;
    }
}

四、Dashboard 负责图形化

package com.itunion.model;import javax.swing.*;import java.awt.*;import java.awt.event.MouseAdapter;import java.awt.event.MouseEvent;import java.text.SimpleDateFormat;import java.util.Date;import java.util.LinkedList;/** * 控制台 */public class Dashboard extends JPanel {    private Master master;    private int i = 0;    public Dashboard() throws HeadlessException, InterruptedException {        super();
        master = new Master(20);        // 每次点击增加一个任务
        addMouseListener(new MouseAdapter() {            @Override
            public void mouseClicked(MouseEvent e) {                for (int j = 0; j < 10; j++) {
                    master.addTask(new Task("任务" + i));
                    i++;
                }
            }
        });
    }    @Override
    public void paint(Graphics g) {        super.paint(g);        int i = 0, x = 10, y = 20;

        y = 30 * i + 20;
        g.drawString(new SimpleDateFormat("提示:点击任意位置增加任务").format(new Date()), x, y + 15);
        i++;

        y = 30 * i + 20;
        g.drawString(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()), x, y + 15);
        i++;

        y = 30 * i + 20;
        g.drawString("队列待消费任务总数:" + master.getTasks().size(), x, y + 15);
        i++;

        LinkedList<Worker> workers = master.getWorkers();        int row = 0;        for (Worker worker : workers) {
            i = row == 10 ? 3 : i;
            x = row < 10 ? 10 : 180;
            y = 30 * i + 20;            boolean isWait = worker.getState() == Thread.State.WAITING;
            g.setColor(isWait ? Color.GREEN : Color.YELLOW);
            g.fillRect(x, y, 150, 20);
            g.setColor(Color.BLACK);            if (isWait || worker.getTask() == null) {
                g.drawString(worker.getName() + " > 等待", x, y + 15);
            } else {
                g.drawString(worker.getName() + " > 执行" + worker.getTask().getName(), x, y + 15);
            }
            row++;
            i++;
        }        // 重新绘制
        repaint();        try {            // 刷新频率
            Thread.sleep(60);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

五、Main 程序的入口

package com.itunion.model;import javax.swing.*;import java.awt.*;public class Main {    public static void main(String[] args) throws InterruptedException {
        JFrame jFrame = new JFrame();
        jFrame.add(new Dashboard(), BorderLayout.CENTER);
        jFrame.setSize(400, 600);
        jFrame.setLocationRelativeTo(null);// 居中
        jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        jFrame.setVisible(true);
    }
}

运行 main 方法后点击窗体任意位置添加任务

总结

我们常用的Thread.sleep() 是线程的休眠,而wait 是Object 的方法,更多的是 资源的等待,不能直接调用线程的 wait 方法

更多精彩内容

架构实战篇(一):Spring Boot 整合MyBatis

架构实战篇(二):Spring Boot 整合Swagger2

架构实战篇(三):Spring Boot 整合MyBatis()

架构实战篇(四):Spring Boot 整合 Thymeleaf

架构实战篇(五):Spring Boot 表单验证和异常处理

架构实战篇(六):Spring Boot RestTemplate的使用

架构实战篇(七):Spring Boot Data JPA 快速入门

架构实战篇(八):Spring Boot 集成 Druid 数据源监控



关注我们

如果需要源码可以关注“IT实战联盟”公众号并留言(源码名称+邮箱),小萌看到后会联系作者发送到邮箱,也可以加入交流群和作者互撩哦~~~!


全部评论: 0

    我有话说:

    Redis线演进

    Redis作为一个基于内存的缓存系统,一直以高性能著称,因没有上下文切换以及无锁操作,即使在单线处理情况下,读速度仍可达到11万次/s,写速度达到8.1万次/s。但是,单线的设计也给Redis

    抖音实战案例使用手册

    实战案例的数据怎么用?看这里!看这里!

    NodeJS 10.5.0 中的线实用介绍

    几天前,Node.js版本10.5.0发布,其中包含的主要功能之一是添加了线支持。

    自学视频剪辑要长时间才能学会?

      <p><strong>雾隐门视频剪辑软件</strong><br /> 雾隐门快剪辑是款非常适合自媒体人士使用视频剪辑软件,快速上手是

    「轻阅读」图解 Java 线生命周期

    Java 线生命周期中都包含哪些状态?生命周期中各个状态都是什么含义?

    面试官:HashMap为什么是线不安全的?

    一直以来只是知道HashMap是线不安全的,但是到底HashMap为什么线不安全?

    架构实战(三)-Spring Boot架构搭建RESTful API案例

    之前分享了Spring Boot 整合Swagger 让API可视和前后端分离架构 受到了大家一致好评 ,本节就接着上节的代码做了详细的查询代码的补充和完善并搭建RESTful API架构案例

    微信小程序实战:商品属性联动选择(案例

    本期的微信小程序实战来做一个电商网站经常用到的-商品属性联动选择的效果,素材参考了一点点

    架构实战(十四):Spring Boot 缓存实战

    场景下的不同缓存策略解决方案

    推荐一款功能强大,开源免费的H5可视编辑器

    H5-Dooring 是一款功能强大,开源免费的H5可视页面配置解决方案,致力于提供一套简单方便、专业可靠、无限可能的H5落地页最佳实践。技术栈以react为主, 后台采用nodejs开发. 预览

    RxJava 3.0.11 发布,Rx 的 Java 实现

    组合在一起,同时抽象了对低级线、同步、线安全...

    MySql实战:正确理解并使用MySql索引

    索引是存储引擎用于快速查找记录的一种数据结构,通过合理的使用数据库索引可以大大提高系统......

    Node实战使用joi来验证数据模型 (十)

    Joi 是 hapijs 自带的数据校验模块,他已经高度封装常用的校验功能,本文就是介绍如何优雅地使用 joi 对数据进行校验......

    架构实战:MyBatis一级、二级,并整合ehcache分布式缓存的使用,附演示实例

    ehcache是一个纯Java的进程内缓存框架,是一种广泛使用的开源Java分布式缓存,具有快速、精干等特点,是Hibernate中默认的CacheProvider。

    架构实战(十六):Spring Boot Assembly服务打包

    使用assembly来打包springboot微服务项目,让发布更简单

    【轻阅读】为什么越来越的系统在做服务

    脱离业务实际情况的架构都是耍流氓,所以不是所有系统都必须服务,也不要为了服务而服务

    抖音品质建设 - iOS启动优化《实战

    前言 启动是 App 给用户的第一印象,启动越慢,用户流失的概率就越高,良好的启动速度是用户体验不可缺少的一环。启动优化涉及到的知识点非常,面也很广,一文章难以包含全部,所以拆分成两部分:原理和

    移动Web实战-使用CSS Sprites减少你的页面http请求

    用户新打开一个网页80%的时间耗费在加载网页内容方面。很多炫酷的网页往往通过图片来展现给用户的,那么页面每加载一张图片就是一个http请求,如果图片过会严重影响图片渲染速度。

    精品推荐:Tomcat优化总结(实战版)

    Tomcat是我们经常使用的 servlet容器之一,甚至很线上产品都使用 Tomcat充当服务器。