生产者与消费者模式:
目的:优化系统性能。
如从远程下载文件,并将这些文件解析。
生产者:启一个或多个线程专门从事下载文件,下载ok的文件放进队列queue中。
消费者:启一个或多个线程专门从事解析文件,从队列queue中拿文件解析。
结构如图:
每个线程做自己的事情,当要用到临界资源Queue时,各个线程抢占资源,一旦有一个线程访问Queue,就阻塞(lock)Queue,等这个线程
访问完Queue后方能解锁。
----------------------------------------------------
如从远程下载文件,并将这些文件解析
代码演示:
----------------------------
自写一个xx.properties,里面是一些配置信息。
username=hello
password=hello
hostname=172.17.206.123
port=21
remotedir=/SIMCard_Manager/
downloaddir=E:/test/
errordir=E:/test/error/
downloadnum=10
resolvenum=0
---------------------------
配置信息类:
public class InitData
{
/**
* ftp登录名
*/
public static final String USERNAME;
/**
* 密码
*/
public static final String PASSWORD;
/**
* host
*/
public static final String HOSTNAME;
/**
* 端口
*/
public static final int PORT;
/**
* ftp端的目录
*/
public static final String REMOTEDIR;
/**
* 下载到本地目录
*/
public static final String DOWNLOADDIR;
/**
* 解析失败存放目录
*/
public static final String RESOLVE_ERROR_DIR;
/**
* 下载线程阻塞文件数
*/
public static final int DOWNLOAD_WAIT_NUM;
/**
* 解析线程阻塞文件数
*/
public static final int RESOLVE_WAIT_NUM;
/**
* 初始化相关配置
*/
static
{
Properties props = DBUtil.getProps();
USERNAME = props.getProperty("username");
PASSWORD = props.getProperty("password");
HOSTNAME = props.getProperty("hostname");
PORT = NumberUtils.toInt(props.getProperty("port"), 21);
REMOTEDIR = props.getProperty("remotedir");
DOWNLOADDIR = props.getProperty("downloaddir");
RESOLVE_ERROR_DIR = props.getProperty("errordir");
DOWNLOAD_WAIT_NUM = NumberUtils.toInt(props.getProperty("downloadnum"), 10);
RESOLVE_WAIT_NUM = NumberUtils.toInt(props.getProperty("resolvenum"), 0);
}
}
----------------------------------------------------
队列类:
public final class LockQueue
{
private static final int MAX_LENGTH = 10;
private static LockQueue instance = new LockQueue();
private List<Object> list = new LinkedList<Object>();
private Lock lock = new ReentrantLock();
private Condition full = lock.newCondition();
private Condition empty = lock.newCondition();
private LockQueue()
{
}
public static LockQueue getInstance()
{
return instance;
}
/**
* 从队列取数据
* <功能详细描述>
* @return
* @see [类、类#方法、类#成员]
*/
public Object getObject()
{
Object t = null;
lock.lock();
try
{
while (0 == list.size())
{
empty.await();
}
t = list.remove(0);
full.signal();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
finally
{
lock.unlock();
}
return t;
}
/**
* 放数据到队列中
* <功能详细描述>
* @param t
* @see [类、类#方法、类#成员]
*/
public void putObject(Object t)
{
lock.lock();
try
{
while (MAX_LENGTH == list.size())
{
full.await();
}
list.add(t);
empty.signal();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
finally
{
lock.unlock();
}
}
}
----------------------------------------------
下载线程
public class RemoteLoadThread extends Thread
{
/**
* 下载队列
*/
private LockQueue lockQueue;
/**
* 线程名
*/
private String threadName;
/**
* ftp
*/
private FTPClient ftpClient;
/**
* 输出流
*/
private OutputStream os;
/**
* 需要下载文件队列
*/
private Queue<String> remoteFiles = new Queue<String>();
public RemoteLoadThread(LockQueue lockQueue)
{
super();
this.lockQueue = lockQueue;
this.threadName = "load ";
remoteFiles.initialize();
if (GeneralUtils.isNull(ftpClient))
{
this.ftpClient = new FTPClient();
}
}
public RemoteLoadThread(LockQueue lockQueue, String threadName)
{
this.lockQueue = lockQueue;
this.threadName = threadName;
remoteFiles.initialize();
if (GeneralUtils.isNull(ftpClient))
{
this.ftpClient = new FTPClient();
}
}
/**
* 获取所有远程解析文件名
* <功能详细描述>
* @return Queue<String>
* @see [类、类#方法、类#成员]
*/
private Queue<String> getRemoteFiles()
{
if (0 == remoteFiles.size())
{
if (getConn())
{
try
{
FTPFile[] file = ftpClient.listFiles(InitData.REMOTEDIR);
for (int i = 0; i < file.length; i++)
{
remoteFiles.putMsg(file[i].getName());
}
}
catch (IOException e)
{
LogUtils.runError(e.getMessage());
}
}
}
return remoteFiles;
}
/**
* 获得ftp连接
* <功能详细描述>
* @return boolean
* @see [类、类#方法、类#成员]
*/
private boolean getConn()
{
boolean result = true;
//登录用户名 密码
try
{
//判断链接ftp服务器是否成功
if (!ftpClient.isConnected())
{
ftpClient.connect(InitData.HOSTNAME, InitData.PORT);
}
ftpClient.login(InitData.USERNAME, InitData.PASSWORD);
//检测连接是否成功
int reply = ftpClient.getReplyCode();
//显示连接失败
if (!FTPReply.isPositiveCompletion(reply))
{
ftpClient.disconnect();
LogUtils.runError("FTP server refused connection");
result = false;
}
}
catch (IOException e)
{
LogUtils.runError(e.getMessage());
}
ftpClient.setControlEncoding(GeneralConstant.CHARACTER_CODING);
FTPClientConfig conf = new FTPClientConfig(FTPClientConfig.SYST_NT);
conf.setServerLanguageCode("zh");
return result;
}
/**
* 下载文件至指定的位置
* 下载文件至系统默认的本地文件夹中
* @param 提供时间戳功能
* @return String
* @see [类、类#方法、类#成员]
*/
private String downloadFile(String name)
{
//时间戳
String time = GeneralUtils.getCurrentTimeStamp();
//本地文件名
String localFileName = name.replace(".txt", time + ".txt");
//本地文件路径
String localFilePath = InitData.DOWNLOADDIR + localFileName;
//远程文件路径
String remoteFilePath = InitData.REMOTEDIR + name;
//本地文件
File localFile = new File(localFilePath);
try
{
os = new FileOutputStream(localFile);
//下载远程文件
ftpClient
.retrieveFile(new String(remoteFilePath.getBytes(GeneralConstant.CHARACTER_GBK), "ISO-8859-1"), os);
}
catch (FileNotFoundException e)
{
LogUtils.runError(e.getMessage());
}
catch (UnsupportedEncodingException e)
{
LogUtils.runError(e.getMessage());
}
catch (IOException e)
{
LogUtils.runError(e.getMessage());
}
return localFileName;
}
/**
* 删除远程文件功能
* 删除ftp上制定文件夹下的SIM卡信息文件,防止重复导入
* @param remoteDir ftp的路径
* @return boolean
* @see [类、类#方法、类#成员]
*/
private boolean removeFile(String remoteDir)
{
boolean flag = true;
try
{
FTPFile[] files = ftpClient.listFiles(remoteDir);
// 删除指定文件夹下所有文件
for (FTPFile f : files)
{
String path = remoteDir + GeneralConstant.SEPARATOR + f.getName();
if (f.isFile())
{
ftpClient.deleteFile(path);
}
}
}
catch (IOException e)
{
e.getMessage();
flag = false;
}
return flag;
}
/**
* 下载ftp文件
* <功能详细描述>
* @see [类、类#方法、类#成员]
*/
public void download()
{
//获取要下载的文件缓存
getRemoteFiles();
if (remoteFiles.size() > 0)
{
//远程有文件
try
{
//获取并移除信息,如果队列为空,则阻塞等待
String fileName = remoteFiles.getMsg();
//下载
fileName = downloadFile(fileName);
//下载好的文件名放进队列
lockQueue.putObject(fileName);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
finally
{
try
{
if (0 == remoteFiles.size())
{
//需要下载的文件都下载完了
//删除远程文件
removeFile(InitData.REMOTEDIR);
ftpClient.logout();
ftpClient.disconnect();
//释放资源
closeSource();
}
}
catch (IOException ioe)
{
LogUtils.runError(ioe.getMessage());
}
}
LogUtils.runInfo("total :>" + remoteFiles.size());
}
else
{
LogUtils.runInfo("远程木有文件");
}
}
/**
* 释放资源
* <功能详细描述>
* @see [类、类#方法、类#成员]
*/
private void closeSource()
{
if (GeneralUtils.isNotNull(os))
{
//释放资源
try
{
os.close();
LogUtils.runInfo("OutputStream close!");
}
catch (IOException e)
{
LogUtils.runError(e.getMessage());
}
}
}
@Override
public void run()
{
while (true)
{
download();
LogUtils.runDebug(threadName + "downLoad is runing...");
}
}
}
---------------------------------------------------
public class AnalyzeThread extends Thread
{
/**
* 下载队列
*/
private LockQueue lockQueue;
/**
* 线程名
*/
private String threadName;
/**
* 解析Ok 缓存队列
*/
private Queue<String> resQueue = new Queue<String>();
public AnalyzeThread(LockQueue lockQueue)
{
super();
this.lockQueue = lockQueue;
resQueue.initialize();
}
public AnalyzeThread(LockQueue lockQueue, String threadName)
{
super();
this.lockQueue = lockQueue;
this.threadName = threadName;
resQueue.initialize();
}
/**
* 解析
* <功能详细描述>
* @see [类、类#方法、类#成员]
*/
public void resolve()
{
try
{
//获取并移除信息,如果队列为空,则阻塞等待
String fileName = (String)lockQueue.getObject();
String path = GeneralUtils.filePathConcat(InitData.DOWNLOADDIR, fileName);
File resFile = new File(path);
//解析文件
boolean result = FileUtil.readFile(resFile);
if (result)
{
//将文件名放进解析成功队列
resQueue.putMsg(fileName);
}
else
{
//将文件名放进解析失败目录里
FileUtils
.copyFile(resFile, new File(GeneralUtils.filePathConcat(InitData.RESOLVE_ERROR_DIR, fileName)));
resFile.delete();
}
}
catch (IOException e)
{
LogUtils.runError(e.getMessage());
}
LogUtils.runInfo("resolve :>" + resQueue.size());
}
@Override
public void run()
{
while (true)
{
resolve();
LogUtils.runDebug(threadName + "resolve is runing...");
}
}
}
-----------------------------------------
test
public class TestMyThread
{
public static void main(String[] args)
{
LockQueue lockQueue = LockQueue.getInstance();
RemoteLoadThread reload = new RemoteLoadThread(lockQueue);
AnalyzeThread analyze = new AnalyzeThread(lockQueue);
reload.start();
analyze.start();
}
}