目的很简单,一个线程负责读取,另一个线程负责写入。每次读取指定大小的byte[],放到一个自己实现的队列中。简单的写了一下,如下:(读取线程)
public class GetThread implements Runnable
{
    private Queue queue = null;
    private int count = 0;
    
    public GetThread(Queue queue, int count)
    {
       this.queue = queue;
       this.count = count;
    }
    
    public void run()
    {
        FileInputStream fis = null;
        try
        {
            fis = new FileInputStream("conf/source.txt");
        }
        catch(Exception e)
        {}
        
        try
        {
            byte[] buffer = new byte[1024];
            while(fis.read(buffer) != -1)
            {
                synchronized(this.queue)
                {
                    if(queue.getCount() < count) //队列有空间
                    {
                        queue.enqueue(buffer);
                        
                        queue.notifyAll();
                    }
                    else
                    {
                        queue.wait();
                    }
                }
                
                buffer = new byte[512];
            }
        }
        catch(Exception ex)
        {}
        finally
        {
            try
            {
                fis.close(); 
            }
            catch(IOException ie)
            {}
            
        }
        
    }}(写入线程)
public class SetThread implements Runnable
{
    private Queue queue = null;
    
    public SetThread(Queue queue)
    {
        this.queue = queue;
    }
    
    public void run()
    {
        FileOutputStream fos = null;
        try
        {
            fos = new FileOutputStream("conf/destination.txt");            while (true)
            {
                byte[] data = null;
                synchronized (this.queue)
                {
                    if (this.queue.getCount() == 0)
                    {
                        this.queue.wait();
                    }
                    data = (byte[]) queue.dequeue();
                }
                
                fos.write(data);
            
            }
        }
        catch(Exception e)
        {}
        finally
        {
            try
            {
                fos.close();
            }
            catch(IOException ie)
            {}
        }
    }
}主函数就不用帖出来了,就是初始化一个读取线程和写入线程,然后启动完事。问题是:如果待拷贝的文件不大,没有问题,但如果文件较大,就会出现只拷贝走一部分数据的情况,源数据文件中剩余的部分就不会被读取,确切说就是在 读取线程 的fis.read(buffer)部分出现问题(红色标注处),文件还没到头,但却返回-1,导致不会继续向Queue中放数据包。不知道是哪个步骤处有问题,诸位大虾帮下忙吧!谢谢啊^_^

解决方案 »

  1.   

    有以下办法解决,
    一,把生产与消费分开,即,读的时候不能写,写的时候不能读,可以分别给它们一个状态,把它们都JOIN到一个主线程里来,用一个状态来区分,保证只有一种状态是活的即可。
    二,当你想要读文件的时候,先把文件挪走或修改一个名子,然后再读,但是这种方法只有在WINDOWS下可行,因为WINDOWS会对文件做线程控制,如果有一个文件正在写或移,程序会报错,如果在其它平台上,系统不对它控制,程序就会出问题。
    三,用队列的方式实现,一个入对,一个出对,入对文件名一定是写好的,消费者只能从队列中去取,但是这种方法不好,因为程序虽然是多线程的,但是过程是单线程的。
      

  2.   

    synchronized (this.queue) 
                    { 
                        if (this.queue.getCount() == 0) 
                        { 
                            this.queue.wait(); 
                        } 
                        data = (byte[]) queue.dequeue(); 
                    } 
                    
                    fos.write(data); 
    是不是写入线程少了唤醒啊?数据出队列以后难道你不唤醒读取线程继续读数据进队列吗?打算让读取线程读满队列后就一直wait吗?另:wait外尽量用循环,保证线程醒后能再次进过条件验证,而不是直接就去“做事”去了,也就是说上面的if语句有安全隐患!
      

  3.   


    对!这是两个问题。写文件后忘了notifyAll;结束条件。
    但~问题是为什么程序运行后,不能将文件正确拷贝下来,只能拷贝一部分?数据文件稍微大点就这样(超过5k),在读文件的线程的fis.read(buffer)处,还没到文件尾部,就已经返回-1了?想不通啊
      

  4.   

    少写了notifyAll会导致在队列读满以后,GetThread 去wait,而且在这里是永久wait下去(因为此处就两个线程是使用queue,SetThread处理后没有唤醒等待的线程),这样就有可能只会读出部分信息。建议先加上notifyAll再测试下如果lz环境中是因为fis.read(buffer)返回了-1而没有读完文件,这就不知道原因了,建议楼主在单线程测试一下读取文件问题,并多用几个文件测试下。
    刚才将你代码修改后测试了N次(jdk1.5,windows xp),在我的环境中copy 5K,220K,13M的文件都没有问题。