用网页前后台来实现生产者消费者,前台用于显示,后台用于实现算法。

来源:互联网 发布:淘宝开网店是免费的吗 编辑:程序博客网 时间:2024/05/19 20:47

暑假小项目:用网页前后台来实现生产者消费者,前台用于显示,后台用于实现算法。
其中涵盖的技术有 jquery、nodejs、java、mysql
话不多说,直接上学习过程。

step one 生产者消费者模型
并发编程把程序划分为多个独立的子任务,通过多线程来驱动。每个线程有创建、就绪、运行、阻塞、死亡五种状态。wait()方法使线程等待,进入阻塞状态。notify()方法唤醒相应的一个线程,使之进入运行状态。notifyall()方法唤醒所有在等待运行的线程。synchronized是同步关键词,当该词修饰的线程在运行时,不允许其他线程运行。thread()类和runnable()接口都是多线程编程的主要方法,主要区别在于在thread()类中类只能继承一个父类,而在runnable()接口中一个类可以继承多个接口。
而生产者消费者模型实质就是生产者生产商品,并存入缓存仓库,消费者从缓存仓库中消费商品,因此每次生产商品时需要创建一个生产线程,消费时创建一个消费线程,再根据缓存仓库的容量,对生产和消费行为进行一定的约束。

step two 结合数据库mysql
网站运行的持久化需要数据库支持,这里运用了关系型数据库mysql。创建过程不再叙述,数据库主键为turn,表明线程的执行顺序,并且修饰了auto_increment自增关键词(因此在清空数据库数据时应该使用truncate而不是delete)。id表示每个线程的属性(为了弄清楚线程运行的不确定性,笔者给每个线程增加了id属性)。num表示该线程生产或消费商品的数量。sum表示执行完该线程后仓库商品的剩余量。效果如下图:

接下来贴出算法代码,简洁起见,只贴出生产者代码。

class Godown {     public static final int max_size = 100; //最大库存量     public int curnum;     //当前库存量     Godown() {     }     Godown(int curnum) {        Connection conn = null;        try {            Class.forName("org.gjt.mm.mysql.Driver");        } catch (ClassNotFoundException e) {            System.out.println("无法加载驱动");            e.printStackTrace();        }        try {            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/procons?characterEncoding=utf8&useSSL=false","root","123456");        } catch (SQLException e) {            System.out.println("无法连接数据库");            e.printStackTrace();        }        try {            Statement stmt = conn.createStatement();            stmt.executeUpdate("insert into storage (id,num,sum) values (0,0," + curnum + ")");            stmt.close();            conn.close();        } catch (SQLException e) {            System.out.println("无法插入初始化数据");            e.printStackTrace();        }        System.out.println(0 + ".目前库存为:" + curnum);        this.curnum = curnum;    }    public synchronized void produce(int id, int neednum) {             //测试是否需要生产         while (neednum + curnum > max_size) {             System.out.println("要生产的产品数量" + neednum + "超过剩余库存量" + (max_size - curnum) + ",暂时不能执行生产任务!");             try {                  wait();             } catch (InterruptedException e) {                 e.printStackTrace();             }         }         //满足生产条件,则进行生产,这里简单的更改当前库存量         curnum += neednum;         Connection conn = null;        try {            Class.forName("org.gjt.mm.mysql.Driver");        } catch (ClassNotFoundException e) {        System.out.println("无法加载驱动");            e.printStackTrace();        }        try {            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/procons?characterEncoding=utf8&useSSL=false","root","123456");        } catch (SQLException e) {            System.out.println("无法连接数据库");            e.printStackTrace();        }        try {            Statement stmt = conn.createStatement();            stmt.executeUpdate("insert into storage(id,num,sum) values("+ id +","+ neednum +","+ curnum +")");            stmt.close();            conn.close();        } catch (SQLException e) {            System.out.println("无法插入生产数据");        }        System.out.println(id + ".已经生产了" + neednum + "个产品,现仓储量为" + curnum);        //唤醒在此对象监视器上等待的所有线程         notifyAll();     }    //消费    public synchronized void consume(int id, int neednum) {……} }
class Producer extends Thread {    private int id;    private int neednum;                //生产产品的数量     private Godown godown;            //仓库     Producer(int id, int neednum, Godown godown) {        this.id = id;        this.neednum = neednum;         this.godown = godown;     }     public void run() {             //生产指定数量的产品             godown.produce(id,neednum);     } }

step three 写html页面
页面写的比较粗劣,能看就行…

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml-transitional.dtd"><html>    <head>        <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />        <script src="jquery-3.1.0.js" type="text/javascript"></script>        <script src="jquery.js" type="text/javascript"></script>    </head>    <body>        <p><input type="submit" id="sub" value="显示" /><input type="button" id="but" value="清空"></p>        <div id="a1"></div>        <div id="a2"></div>        <div id="a3"></div>        <div id="a4"></div>    </body></html>

step four 搭建nodejs服务器
搭建nodejs服务器是最后一步,我的想法是触发网页上click事件,通过使用mysql模块读取后台数据库的数据并显示到网页上。mysql模块比较简单,通过建立一个connection,使用connect()、query()、end()等方法便能使用。而页面与服务器的交互,得到学长的建议,我使用了websocket。websocket是html5的新协议,实现了浏览器和服务器的全双工通信。首先通过已封装好的握手协议,实现浏览器的请求和服务器的回应,涉及http协议。握手成功后有许多操作,比如我写在前端的jquery部分,有onopen、onerror、onmessage(接收服务器传过来的数据)、onclose, node端有on(接收浏览器数据并处理)。
如下为nodejs代码:

var express = require('express');var mysql = require('mysql');var ws = require('ws').Server;var app = express();var data = new Array();app.use(express.static(__dirname + '/public'));app.set('port', process.env.PORT || 3000);//数据库连接var connection = mysql.createConnection({    host:'localhost',    user:'root',    password:'123456'});var server = new ws({host:"127.0.0.1",port:3000});server.on('connection',function(ws) {    console.log('new connection founded successfully');    //接收数据并处理    ws.on('message',function(e) {        if (e==1) {            connection.connect();            connection.query('use procons');            connection.query('select * from storage',function selectCb(err,results,fields){                if (err) {                    throw err;                }                if (results) {                    for (var i = 0; i < results.length; i++) {                        data[i] = results[i].turn+'    '+results[i].id+'  '+results[i].num+'  '+results[i].sum;                        ws.send(data[i]);                    }                }            });            connection.end();                       }/*      if (e==2) {            connection.connect();            connection.query('use procons');            connection.query('truncate table storage',function(err,result){                if (err) {                    throw err;                }                if (result) {                    ws.send(null);                }            });            connection.end();        }       */    }); });console.log('websocket-server running...');app.listen(app.get('port'), function(){  console.log( 'Express started on http://localhost:' + app.get('port') + '; press Ctrl-C to terminate.' );});

以及jquery文件:

var bool;var ws = new WebSocket('ws://127.0.0.1:3000');ws.onopen = function() {    $("#a1").append("<p>连接建立</p>");    }ws.onerror = function() {    $("#a3").append("<p>连接错误</p>");}//接收从服务器发来的数据       ws.onmessage = function(e) {    $("#a2").append('<p>'+e.data+'</p>');}ws.onclose = function() {    $("#a4").append("<p>连接关闭</p>");}$(function() {     $("#sub").click(function() {        $("#a2").append("<p>turn id num sum</p>");        bool = 1;        ws.send(bool);    });    $("#but").click(function() {        $("#a2").remove();    })})

网页上的显示结果为:
这里写图片描述

至此,一个简单的前后端交互的生产者消费者模型就完成了。粗劣地完成后,笔者就卸甲归家了,还有很多细节和功能都有待完善,之后再改善了,不过这也是笔者第一次独立完成的小项目,意义非凡。

1 0
原创粉丝点击