记录一个ByteBuffer在多线程下存取的简单应用
2017-09-25 01:29
393 查看
周末去前公司讲解了一段很久以前的代码(当时交接的人早就走了,后来也不知道他们什么情况),顺便帮另一位同事解决数据存取的问题。
需求是这样的:安卓录制音视频,C调用Java方法传递一段不定长度的
把ByteBuffer当作一个货物的中转点,遵循先进先出的规则将所有货物依次有序的堆放在中转点,以便下次转出。转入和转出的工作是由两个不同的车队去完成,考虑到这一点,应该使用异步的方式来存取这批货物。
再定义数据读取结束的标识:
* limit始终为ByteBuffer最大容量,也就是上限;*
* remaining则表示为ByteBuffer的空余容量。*
需求是这样的:安卓录制音视频,C调用Java方法传递一段不定长度的
short[]类型数据,要求是按照每段2048字节格式传递给另一个API。最好的方式是实现存储字节的队列,但简单利用ByteBuffer来操作一下也是相当便捷的。
把ByteBuffer当作一个货物的中转点,遵循先进先出的规则将所有货物依次有序的堆放在中转点,以便下次转出。转入和转出的工作是由两个不同的车队去完成,考虑到这一点,应该使用异步的方式来存取这批货物。
简述
这段代码主要利用ByteBuffer的compact()方法,将数据前移,保证ByteBuffer有足够的空间存新数据的同时,也能够将旧的数据从ByteBuffer中逐端取出,实现先进先出的队列效果。
常量定义
定义基本规则常量,为调试直观,常量取值范围都比较小:// 限制ByteBuffer最大容量 final static int BUFFER_SIZE = 8888; // 定义全局ByteBuffer final static ByteBuffer DATA_BUFFER = ByteBuffer.allocate(BUFFER_SIZE); // 定义每次将要存到ByteBuffer中的数据长度 1000~3000 final static int WRITE_LEN = 000; // 定义每次从ByteBuffer读取的数据长度 final static int READ_LEN = 2048; // 同步锁 final static Lock LOCK = new ReentrantLock(true); // 表示数据读取是否结束 static boolean readEnd = false;
再定义数据读取结束的标识:
// 表示数据读取是否结束 static boolean readEnd = false;
main方法
将存取作为两个线程去执行,通过ByteBuffer(中转站)的方式,将一个文件(货物)copy为另一个文件(转运终点):public static void main(String[] args) throws Exception { File readFile = new File(""); File writeFile = new File(""); new PutBufferThread(readFile).start(); new GetBufferThread(writeFile).start(); }
三个重要属性:
* position在本段代码中,始终表现为有效数据长度;** limit始终为ByteBuffer最大容量,也就是上限;*
* remaining则表示为ByteBuffer的空余容量。*
PutBufferThread,将数据存到ByteBuffer中
PutBufferThread,表现为货物转入车队,货物转入到中转站前,会先询问中转站是否还有足够的空间用来存放本次运输的货物,空间不足或者转出车队正在装货,就稍作等待。public class PutBufferThread extends Thread { private InputStream in; PutBufferThread(File file) { try { this.in = new FileInputStream(file); } catch (FileNotFoundException e) { e.printStackTrace(); } } @Override public void run() { try { byte[] b = new byte[WRITE_LEN]; while (true) { LOCK.lock(); // 锁住 然后检查一下remaining // 检查ByteBuffer剩余容量是否能存放一次指定长度的数据 if (DATA_BUFFER.remaining() >= WRITE_LEN) { // 从文件中读出一段数据 if (in.read(b, 0, b.length) == -1) { LOCK.unlock();// 如果文件读取结束,直接解锁并结束循环 break; } // put进ByteBuffer DATA_BUFFER.put(b, 0, len); } LOCK.unlock(); // 解锁 } readEnd = true; // 文件读取结束 in.close(); // 关闭文件流 } catch (IOException e) { e.printStackTrace(); } } }
GetBufferThread,从ByteBuffer中取出数据
GetBufferThread表现为转出车队,转出前询问是否有足量的货物运输,这里定义为2048。货物不足或转出车队正在卸货时稍作等待。public class GetBufferThread extends Thread { private OutputStream out; public GetBufferThread(File file) { try { this.out = new FileOutputStream(file); } catch (FileNotFoundException e) { e.printStackTrace(); } } @Override public void run() { byte[] data = null; int length = 0; while (true) { // 获取有效数据长度 length = DATA_BUFFER.position(); if (length > 0) { // 如果长度不足2048,且还没有读取结束时,立即开始下一次循环。 if (length < READ_LEN && !readEnd) { continue; } // 如果数据长度超出2048,则只取2048部分 if (length > READ_LEN) { length = READ_LEN; } // 读取数据前,锁定 LOCK.lock(); data = new byte[length]; // 将ByteBuffer状态设置为准备读取数据。 DATA_BUFFER.flip(); DATA_BUFFER.get(data); // 取出数据 // 将ByteBuffer中的剩余数据前移,“删除”已取出的部分 DATA_BUFFER.compact(); LOCK.unlock(); // 解锁 } else if (readEnd) { //如果文件读取结束,且ByteBuffer中没有数据,挑出循环 break; } if (length > 0) { // 将数据存到文件中 try { out.write(data, 0, length); out.flush(); } catch (IOException e) { e.printStackTrace(); } } } DATA_BUFFER.clear(); // 清空缓冲区 if (out != null) { try { out.close(); // 关闭流 } catch (IOException e) { e.printStackTrace(); } } } }
相关文章推荐
- 《解决问题1000.1》又是I2C驱动问题,产品应用上一个问题,非常简单,也比较典型,记录一下
- ByteBuffer简单应用之ByteBuffer知多少?
- 网络编程与多线程的应用--基于socket udp编写一个简单聊天程序
- MAC COCOA一个简单的多线程程序
- python多线程中互斥锁Threading.Lock的简单应用
- 使用C#开发一个简单的P2P应用
- 有效背单词的一个简单算法(一)——SugarMemo算法学习记录
- Angular5初探之--构建一个简单的单页应用,包含登录(login)和几个一级菜单
- 一个不错的多线程Socket服务器简单例子
- iOS开发UI篇—使用xib自定义UItableviewcell实现一个简单的团购应用界面布局
- 多线程学习--写一个简单的缓存系统
- .NET MSChart应用的一个简单例子
- Flatpak打包(6)——构建一个简单的应用
- 多线程的简单应用----彩票摇号器
- CSS布局中一个简单的应用BFC的例子
- PWA(渐进式网页应用) + SPA(但也应用)的一个简单的思考
- oracle中某列连续相同值的记录数统计(一个简单的例子)
- Java WEB之Servlet学习之路(一)一个最简单的Servlet应用
- Android安装应用和跳转应用简单记录
- 一个简单的鸽巢原理的应用