Java中Volatile关键字解决Android中的线程BUG!
发布日期:2021-07-01 00:00:25
浏览次数:3
分类:技术文章
本文共 5463 字,大约阅读时间需要 18 分钟。
前言
在android 中最常见的就是线程操作
最近在调试小票打印机器的时候 开启了一个线程随时准备着打印小票 结果出现了bug 在打印的时候 不能控制打印的次数 还有线程执行的顺序在徘徊了几天后,在查阅资料时看到了java中的关键字 Volatile
Volatile 特性
当一个变量定义为 volatile 之后,将具备两种特性:
1.保证此变量对所有的线程的可见性,这里的“可见性”,如本文开头所述,当一个线程修改了这个变量的值,volatile 保证了新值能立即同步到主内存,以及每次使用前立即从主内存刷新。但普通变量做不到这点,普通变量的值在线程间传递均需要通过主内存(详见:Java内存模型)来完成。
2.禁止指令重排序优化。有volatile修饰的变量,赋值后多执行了一个“load addl $0x0, (%esp)”操作,这个操作相当于一个内存屏障(指令重排序时不能把后面的指令重排序到内存屏障之前的位置),只有一个CPU访问内存时,并不需要内存屏障;(什么是指令重排序:是指CPU采用了允许将多条指令不按程序规定的顺序分开发送给各相应电路单元处理)。
volatile 性能:
volatile 的读性能消耗与普通变量几乎相同,但是写操作稍慢,因为它需要在本地代码中插入许多内存屏障指令来保证处理器不发生乱序执行。
代码片
首先在初始化变量的时候 我们给一个volatile 修饰的boolean值
volatile boolean printFlag = false;
在我们拿到打印数据的线程中 我们将变量printFlag
置为true
if (bean != null && bean.size() > 0) { mOrderDetailBeans = bean; //拿到数据 设置为true printFlag = true; }
然后我们开一个线程 无线等待数据 拿到数据就打印小票
new Thread(() -> { Looper.prepare(); try { while (true) { if (mUsbDriver != null) { try { //这里修饰Volatile 为true才走打印数据 while (printFlag) { ShowPrintClick(); Log.e(TAG, " === >>> 执行打印数据"); } } catch (Exception e) { Message message = new Message(); message.what = 4; message.obj = e.getMessage(); mMyHandler.sendMessage(message); } } else { Thread.sleep(1000); } } } catch (Exception e) { e.printStackTrace(); } Looper.loop(); }).start();
ShowPrintClick 方法代码
try { Message message = Message.obtain(); message.what = 4; message.obj = "极客多功能售药机"; mMyHandler.sendMessage(message); if (printFlag && mOrderDetailBeans.size() > 0) { mUsbDriver.write(PrintCmd.SetReadZKmode(0)); mUsbDriver.write(PrintCmd.PrintFeedDot(30)); StringBuffer header = new StringBuffer(); header.append(" 鑫斛药庄八店 " + lineEnd); header.append(" 买药买放心 放心到鑫斛药庄 " + lineEnd); header.append("------------------------------------------------" + lineEnd); header.append(lineEnd); header.append("购买日期:" + getNowDate() + lineEnd); header.append("订单编号:" + ordersNum); mUsbDriver.write(PrintCmd.PrintString(header.toString(), 0)); OrderDetailBean orderDetailBean; StringBuffer body = new StringBuffer(); int totalNum = 0; double totalPrice = 0; for (int i = 0; i < mOrderDetailBeans.size(); i++) { orderDetailBean = mOrderDetailBeans.get(i); body.append(lineEnd); body.append("药品名称:" + (("").equals(orderDetailBean.getGoodsName()) ? "" : orderDetailBean.getGoodsName()) + lineEnd); body.append("生产厂家:" + (("").equals(orderDetailBean.getManufacturer()) ? "" : orderDetailBean.getManufacturer()) + lineEnd); body.append("规格:" + (("").equals(orderDetailBean.getSpec()) ? "" : orderDetailBean.getSpec()) + lineEnd); body.append("批号:" + (("").equals(orderDetailBean.getBatchNum()) ? "" : orderDetailBean.getBatchNum()) + lineEnd); body.append("有效期:" + (("").equals(orderDetailBean.getExpireDateTime()) ? "" : orderDetailBean.getExpireDateTime()) + lineEnd); body.append("数量:" + orderDetailBean.getQuantity() + lineEnd); body.append("金额:" + orderDetailBean.getAmount()); body.append(lineEnd); //这里是计算购买的总商品数 totalNum += orderDetailBean.getQuantity(); //累加总消费 totalPrice = CalcUtils.addDouble(totalPrice, orderDetailBean.getAmount()); } mUsbDriver.write(PrintCmd.PrintString(body.toString(), 0)); //打印总数量和总价格 StringBuffer total = new StringBuffer(); total.append("合计数量:" + totalNum + lineEnd); total.append("合计金额:" + totalPrice + lineEnd); mUsbDriver.write(PrintCmd.PrintString(total.toString(), 0)); body.append(lineEnd); //打印地址 StringBuffer address = new StringBuffer(); address.append("------------------------------------------------" + lineEnd); address.append("本小票为重打印,不做开票依据" + lineEnd); address.append("地址:重庆市九龙坡区石坪桥正街2号1-2、3#" + lineEnd); address.append("电话:023-72223575" + lineEnd); address.append("药品是特殊商品,一经售出概不退换"); mUsbDriver.write(PrintCmd.PrintString(address.toString(), 0)); mUsbDriver.write(PrintCmd.PrintFeedline(5)); mUsbDriver.write(PrintCmd.PrintCutpaper(1)); //打印完了 再把printFlag设置为false 意思为只执行一次打印数据 printFlag = false; } } catch (Exception e) { Message message = Message.obtain(); message.what = 4; message.obj = e.getMessage(); mMyHandler.sendMessage(message); }
总结
温故而知新,可以为师矣!
哈哈哈~转载地址:https://lvshichunqiu.blog.csdn.net/article/details/113130480 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!
发表评论
最新留言
留言是一种美德,欢迎回访!
[***.207.175.100]2024年04月22日 03时29分56秒
关于作者
喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
Java Stream 使用
2019-05-01
Flink 的DataStream 和 DataSet区别
2019-05-01
Flink源码学习
2019-05-01
MYSQL 表的手动更新统计分析记录
2019-05-01
MYSQL的身体,POSTGRESQL 的头脑
2019-05-01
PostgreSQL 高可用Patroni和学习方法
2019-05-01
业务卡单 与 MongoDB性能记录与分析
2019-05-01
MYSQL 中的查询技巧 与 MYSQL 8 并行查询
2019-05-01
MYSQL 8 Serialized Dictionary Information
2019-05-01
java多线程-基础知识
2019-05-01
java多线程-基本的操作及状态分析
2019-05-01
java多线程-Thread类的一些基本API
2019-05-01
java多线程-线程的同步
2019-05-01
java多线程-原子性,有序性,可见性
2019-05-01
java多线程-(无锁)CAS算法基础
2019-05-01
commons-csv的基本操作
2019-05-01
java 多线程之Exchanger
2019-05-01
java 多线程之Future与FutureTask
2019-05-01
rocketmq(broker配置参数设置)不断更新中
2019-05-01