多个线程向一个文件写数据

package com.bean;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
/**
 * 多个线程向一个文件写数据
 */
public class ThreadDemo
{
    static Write write = new Write(); 
    public static void main(String[] args)
    {
        String path = "C:\\Users\\DOG\\Desktop\\aa.txt";
        String message1 = Thread.currentThread().getName()+":hello";
        String message2 = "world";
        //创建100个线程
        for(int i=0;i<100;i++){
            new Thread(new Runnable(){
                @Override
                public void run(){
                    write.write(path, message1,message2);
                }
            }).start();
        }
    }
}
class Write
{
    public synchronized void write(String path,String message1,String message2){
        FileWriter writer = null;
        try {
            File file = new File(path);
            writer = new FileWriter(file,true);//追加写入
            writer.write(message1);
            Thread.sleep(100);
            writer.write(message2+"\n");
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        } finally {
            if(writer != null){
                try {
                    writer.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }   
}


写到文件里如下:

main:helloworld
main:helloworld
main:helloworld
main:helloworld
main:helloworld
main:helloworld
main:helloworld
main:helloworld
main:helloworld
main:helloworld
...

可以看出代码是线程安全的,没有出现写乱的情况,但是把Write类的write方法上的synchronized关键字去掉,发现写入文件里也是和没去掉synchronized关键字时一样的效果,跟踪java.io.FileWriter的write方法:

public void write(String str) throws IOException {
        write(str, 0, str.length());
}

public void write(String str, int off, int len) throws IOException {
        synchronized (lock) {
            char cbuf[];
            if (len <= WRITE_BUFFER_SIZE) {
                if (writeBuffer == null) {
                    writeBuffer = new char[WRITE_BUFFER_SIZE];
                }
                cbuf = writeBuffer;
            } else {    // Don't permanently allocate very large buffers.
                cbuf = new char[len];
            }
            str.getChars(off, (off + len), cbuf, 0);
            write(cbuf, 0, len);
        }
    }

发现write方法里有synchronized代码块,锁为当前对象(lock),因为写入文件的操作只new了一个FileWriter对象(new FileWriter(file,true);),所以所有的线程竞争同一把锁,自然也就是线程安全的了,但是如果写的操作new了多个FileWriter对象,就会出现写乱的情况,因为不是竞争的同一把锁,如下:

class Write
{
    public void write(String path,String message1,String message2){
        FileWriter writer1 = null;
        FileWriter writer2 = null;
        try {
            File file = new File(path);
            //new两个FileWriter对象
            writer1 = new FileWriter(file,true);//追加写入
            writer2 = new FileWriter(file,true);//追加写入
            writer1.write(message1);
            Thread.sleep(100);
            writer2.write(message2+"\n");
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        } finally {
            if(writer1 != null){
                try {
                    writer1.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(writer2 != null){
                try {
                    writer2.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }   
}

写到文件里如下:

main:hellomain:helloworld
world
main:hellomain:helloworld
world
main:hellomain:hellomain:helloworld
world
world
main:hellomain:hellomain:hellomain:hellomain:hellomain:hellomain:hellomain:hellomain:helloworld
world
world
world
main:hellomain:hellomain:helloworld
...

可以发现文件写乱了,线程不安全,因为竞争的不是同一把锁对象。如果在Write类的write方法上加上synchronized关键字,可以发现写入不乱了,因为这个synchronized关键字的锁对象为main方法里的write对象(static Write write = new Write();),锁为同一把锁,线程安全。但是每个线程new一个Write对象,发现线程是不安全的,代码和结果如下:

package com.bean;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
/**
 * 多个线程向一个文件写数据
 */
public class ThreadDemo
{
//  static Write write = new Write(); 
    public static void main(String[] args)
    {
        String path = "C:\\Users\\DOG\\Desktop\\aa.txt";
        String message1 = Thread.currentThread().getName()+":hello";
        String message2 = "world";
        //创建100个线程
        for(int i=0;i<100;i++){
            new Thread(new Runnable(){
                @Override
                public void run(){
                    new Write().write(path, message1,message2);
                }
            }).start();
        }
    }
}
class Write
{
    public synchronized void write(String path,String message1,String message2){
        FileWriter writer1 = null;
        FileWriter writer2 = null;
        try {
            File file = new File(path);
            //new两个FileWriter对象
            writer1 = new FileWriter(file,true);//追加写入
            writer2 = new FileWriter(file,true);//追加写入
            writer1.write(message1);
            Thread.sleep(100);
            writer2.write(message2+"\n");
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        } finally {
            if(writer1 != null){
                try {
                    writer1.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(writer2 != null){
                try {
                    writer2.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }   
}

写到文件里如下:

main:hellomain:hellomain:hellomain:hellomain:hellomain:helloworld
world
world
world
world
world
main:hellomain:helloworld
world
main:hellomain:hellomain:helloworld
world
main:helloworld
world
main:helloworld
main:hellomain:hellomain:helloworld
...

因为多个线程调用Write类的write方法时,每个线程用了一个Write对象,锁对象不是同一个,线程是不安全的。

你可能感兴趣的:(多线程)