作者adrianshum (Alien)
看板java
标题Re: [问题] Java Multithreading Writ/Read/Create
时间Mon Oct 22 22:43:15 2012
※ 引述《tnsshnews (tnsshnews)》之铭言:
: Dear all,
: 小弟为Multithreading新手一位, 过去鲜少写过多执行序的问题。
: 目前程式执行需要三个执行序:
: Thread-1: 持续监听网路封包
: Thread-2: 一有新封包接收到, 立刻写入档案
: Thread-3: 每隔五分钟产生一个新档案(.bak), 任何新收到的封包,写入最
: 产生的档案里,
: 等一个五分钟的新档案产生之後, 上一个档案的.bak便取消掉
: (.bak的目的是确保该档案目前还未关闭)
这样做不是不可以,只是个人觉得这三个动作未至於独立到要分开
thread做,单 thread 就可以写得很有条理了。anyway, 後面继续
: 小弟目前做法是:
: Thread-1: 每个几秒钟, 就询问server, 是否有新封包, 如果有, 便一直塞入List中
: Thread-2: 利用loop一直扫描Thread-1的List, BufferWriter写入档案, 并将以写入
: 档案的资料从List删除(确保List中资料都是未写入档案的)
建议避免这样做 polling.
Java 本身就有现成好用的 producer-consumer queue (BlockingQueue)
: Thread-3: 每隔五分钟产生新档案(.bak), 并将五分钟内接收的新资料写入该档案,
: 下一个五分钟产生新档案时, 将上一个五分钟产生的档案改档名
: (取消.bak), 关闭BufferWriter指向,
: 并将Thread-2的BufferWriter指向新的档案(新的.bak)
: 目前已经完成差不多, 但测试时发现多问题
: 1. 如果一边有新资料进来, 一边又写入档案, 会不会造成非同步呢?
: 目前我是将写过的资料, 从List删除, 这样可确保留在List的资料都是尚未写入的,
: 但总觉得这样写很不漂亮!!
改用 blocking queue,效果就是:
Thread 1 一直写入新的 item
Thread 2 一直从 queue 取得新的 item 写进档案。
看起来就整洁许多。
用 List 也差不多,只是你要小心 synchronize 的问题。
直接用 ArrayList你会死很惨
: 2. 因为每五分钟换一次档案, 所以写档案的Thread, 不会关掉BufferWriter,
: 但没关掉
: 就不能改档名。目前机制是, 还没有换档前, 档案一直会有新资料写进来,
: 因为产生的档案是要给另一只程式读的, 为了避免另一只程式不会读到不
: 完整的资料,
: 所以采取这样的手法, 但也觉得这样不够漂亮@@
: 感激不尽!!
最基本的改法是加入适当的 synchronization control.
在写档时,改档案的 thread 就乖乖等;改档案时,就轮写档的
thread 在等。
由於 Writer 或会丢弃,直接 synchronize writer 未必太适合,
可以弄一个 semaphore,或弄一个 dummy obj 作 mutex, 然後
写档前及改档前就 lock
更进一步,为了让程式更好维护,不妨把这部份包得好看一点,比如:
class DataItemOutput {
private Writer writer;
publc
synchronized void writeItem(DataItem item) {
writer.write(item.toString());
}
public
synchronized void rollFile() {
writer.close();
// .... 开新 writer, 删旧档 etc
}
}
这样 thread 2 & 3 都变得很简单:
Thread2:
while (!end) {
DataItem item = dataItemQueue.take();
dataItemOutput.writeItem(item);
}
Thread3:
while (!end) {
sleep(5 minutes);
dataItemOutput.rollFile();
}
再更一步,Thread3 可以用 TimerTask, ScheduledExecutorService 之类
然後再更进一步,你会发觉 roll file 的 thread 其实是多余的。
只要你在 DataItemOutput.writeItem() 里,检查一下现在的 file
是什麽时候开,这五分钟就开新并纪绿新时间,Thread3 根本就没有
存在必要了:
class DataItemOutput {
private Writer writer;
private Date fileTime;
publc void writeItem(DataItem item) {
if (currentTime > fileTime + 5minutes) {
rollFile();
}
writer.write(item.toString());
}
public void rollFile() {
writer.close();
// .... 开新 writer, 删旧档 etc
fileTime = currentTime;
}
}
--
※ 发信站: 批踢踢实业坊(ptt.cc)
◆ From: 223.19.45.198