记录一个ByteBuffer在多线程下存取的简单应用
来源:互联网 发布:求职简历邮件正文知乎 编辑:程序博客网 时间:2024/06/06 05:30
周末去前公司讲解了一段很久以前的代码(当时交接的人早就走了,后来也不知道他们什么情况),顺便帮另一位同事解决数据存取的问题。
需求是这样的:安卓录制音视频,C调用Java方法传递一段不定长度的short[]
类型数据,要求是按照每段2048字节格式传递给另一个API。最好的方式是实现存储字节的队列,但简单利用ByteBuffer来操作一下也是相当便捷的。
把ByteBuffer当作一个货物的中转点,遵循先进先出的规则将所有货物依次有序的堆放在中转点,以便下次转出。转入和转出的工作是由两个不同的车队去完成,考虑到这一点,应该使用异步的方式来存取这批货物。
简述
这段代码主要利用ByteBuffer的compact()
方法,将数据前移,保证ByteBuffer有足够的空间存新数据的同时,也能够将旧的数据从ByteBuffer中逐端取出,实现先进先出的队列效果。
常量定义
定义基本规则常量,为调试直观,常量取值范围都比较小:
// 限制ByteBuffer最大容量final static int BUFFER_SIZE = 8888;// 定义全局ByteBufferfinal static ByteBuffer DATA_BUFFER = ByteBuffer.allocate(BUFFER_SIZE);// 定义每次将要存到ByteBuffer中的数据长度 1000~3000final 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(); } } }}
- 记录一个ByteBuffer在多线程下存取的简单应用
- 在 RH9 下存取 Windows 下的共享文件夹
- ExtJs在IE下存在的一个bug
- ByteBuffer的简单实例
- Java多线程--深入剖析单例模式下存在的线程安全问题
- 在Spring环境下存取properties文件中的值
- 在Spring环境下存取properties文件中的值
- 在Spring环境下存取properties文件…
- 关于WebLogic下存取Oracle的BLOB字段
- jquery在form表单取值的简单应用
- 多线程的简单应用
- 多线程的简单应用
- 怎样在一个时间段内记录,只取最早的一条记录?
- 一个简单的多线程
- 页面在不同屏幕分辨率下存在的问题及解决办法
- 页面在不同屏幕分辨率下存在的问题及解决办法
- 页面在不同屏幕分辨率下存在的问题及解决办法
- ByteBuffer.allocate()和ByteBuffer.allocateDirect在性能上的差异
- Servlet——了解Java Servlet技术
- MHN开源蜜罐安装踩坑以及golang升级
- 86. Partition List
- CyclicBarrier
- hadoop能用到的系统端口
- 记录一个ByteBuffer在多线程下存取的简单应用
- 小四旋翼无人机学习日记(一)
- Python3从入门到放弃
- 接上文,终于解决了mamp安装扩展的问题.
- ssh中难理解的问题总结(一)-关于hibernate中的sessionFactory与http中的session
- 链表中倒数第k个结点
- JSP——了解Jsp技术
- 【Git】git的高级用法
- FTP连接时出现“227 Entering Passive Mode”