文件读写冲突进程锁FileLock和线程锁ReentrantReadWriteLock

进程文件锁FileLock

FileLock是是进程级别的锁,可以保证不同的进程来对文件读写互斥,进程一般也就是指一个main函数对应一个jvm。在windows下,进程锁存在,但是在linux下,进程锁不存在,也就是说不同进程可以同时读写一个文件。
读文件:

//读文件函数
package testjzx;
import java.io.*;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.util.Calendar;

public class Read2 {
public static void read() {
 try {//读取文件
            Calendar calstart = Calendar.getInstance();
            //Thread.sleep(3);
            File file = new File("D:/1_1_1_1_1_0.json");
            FileInputStream fis = new FileInputStream(file);
            FileChannel fcin = fis.getChannel();
            FileLock flin = null;
            while (true) {
                flin = fcin.tryLock(0, Long.MAX_VALUE, true);
                if (flin != null) {
                    break;
                } else {
                    System.out.println("有写线程正在操作该文件,当前线程休眠10毫秒");
                    Thread.sleep(10);
                    continue;
                }
            }
            System.out.println("开始读文件!");
            InputStreamReader inputStreamReader = new InputStreamReader(fis, "UTF-8");
            BufferedReader reader = new BufferedReader(inputStreamReader);
            StringBuffer sb = new StringBuffer();
            String tempString = null;
            while ((tempString = reader.readLine()) != null) {//按行读取
                sb.append(tempString);
            }
            System.out.println(sb.toString());
                System.out.println("读文件结束" );
                Calendar calend = Calendar.getInstance();
                System.out.println("读文件共花了" + (calend.getTimeInMillis() - calstart.getTimeInMillis()) + "毫秒");
                reader.close();
               // flin.release();//释放锁有两种方式,关闭通道,或者调用lock的release()方法。
                fcin.close();
                fis.close();
                fis = null;
            //Thread.sleep(10);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

写文件:

package testjzx;

import com.alibaba.fastjson.JSONArray;
import utils.DataAcquisition;

import java.io.*;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.util.Calendar;
import java.util.List;

import static agent.eventProcessor.ParameterConfigTest.getAllConfig;
public class Write2 {
    public static int flag=0;
    public static void write()
    {
        try {
            Calendar calstart = Calendar.getInstance();
            File file = new File("D:/1_1_1_1_1_0.json");
            if (!file.exists())
                file.createNewFile();

            //对该文件加锁
            FileOutputStream out = new FileOutputStream(file);
            FileChannel fcout = out.getChannel();
            FileLock flout = null;
            while (true) {
                flout = fcout.tryLock();
                if (flout != null) {
                    break;
                } else {
                    System.out.println("有读线程正在操作该文件,当前线程休眠10毫秒");
                    Thread.sleep(10);
                    continue;
                }
            }
            System.out.println("开始写文件!");
            flag++;
            if(flag>2)
                flag=flag-3;
            List<String> config = getAllConfig(flag);
            JSONArray datamap = DataAcquisition.getQueryDatamap(config);
            String jsonstring=datamap.toJSONString();
            System.out.println("文件内容:"+jsonstring);
            OutputStreamWriter writer = new OutputStreamWriter(out, "UTF-8");
            BufferedWriter bufferedWriter = new BufferedWriter(writer);
            bufferedWriter.write(jsonstring);
            bufferedWriter.flush();
            bufferedWriter.close();
            System.out.println("写文件结束!");
            Calendar calend = Calendar.getInstance();
            System.out.println("写文件共花了" + (calend.getTimeInMillis() - calstart.getTimeInMillis()) + "毫秒");
            //flout.release();//释放锁有两种方式,关闭通道,或者调用lock的release()方法。
            fcout.close();
            out.close();
            out = null;
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    }

读线程:

package testjzx;
import java.io.*;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.util.Calendar;
public class Read extends Thread{
public void run() {
    while (true) {
        try {
            Read2.read();
            sleep(10);
        }catch(InterruptedException e) {
            e.printStackTrace();
        }
    }
}
        }

写线程:

package testjzx;
import java.io.*;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.util.Calendar;
public class Write extends Thread{
public void run() {
    while (true) {
        try {
            Write2.write();
            sleep(10);
        }catch(InterruptedException e) {
            e.printStackTrace();
        }
    }
}
        }

然后用两个main函数(两个线程)分别开启读写线程即可。

线程锁ReentrantReadWriteLock

现实中有这样一种场景:对共享资源有读和写的操作,且写操作没有读操作那么频繁。在没有写操作的时候,多个线程同时读一个资源没有任何问题,所以应该允许多个线程同时读取共享资源;但是如果一个线程想去写这些共享资源,就不应该允许其他线程对该资源进行读和写的操作了。

针对这种场景,JAVA的并发包提供了读写锁ReentrantReadWriteLock,它表示两个锁,一个是读操作相关的锁,称为共享锁;一个是写相关的锁,称为排他锁,描述如下:

线程进入读锁的前提条件:

没有其他线程的写锁,

没有写请求或者有写请求,但调用线程和持有锁的线程是同一个。

线程进入写锁的前提条件:

没有其他线程的读锁

没有其他线程的写锁

读写文件:

package testjzx.testjzx2;
import com.alibaba.fastjson.JSONArray;
import utils.DataAcquisition;
import java.io.*;
import java.util.Calendar;
import java.util.List;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import static agent.eventProcessor.ParameterConfigTest.getAllConfig;
public class Service {
    private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
    public static int flag=0;
    public void read() {
        try {
            try {
                lock.readLock().lock();
                System.out.println("获取读锁" + Thread.currentThread().getName());
                Calendar calstart = Calendar.getInstance();
                File file = new File("D:/1_1_1_1_1_0.json");
                FileInputStream fis = new FileInputStream(file);
                System.out.println("开始读文件!");
                InputStreamReader inputStreamReader = new InputStreamReader(fis, "UTF-8");
                BufferedReader reader = new BufferedReader(inputStreamReader);
                StringBuffer sb = new StringBuffer();
                String tempString = null;
                while ((tempString = reader.readLine()) != null) {//按行读取
                    sb.append(tempString);
                }
                System.out.println("文件内容:"+sb.toString());
                Calendar calend = Calendar.getInstance();
                System.out.println("读文件共花了" + (calend.getTimeInMillis() - calstart.getTimeInMillis()) + "毫秒");
            } finally {
                lock.readLock().unlock();
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public void write() {
        try {
            try {
                lock.writeLock().lock();
                System.out.println("获取写锁" + Thread.currentThread().getName());
                Calendar calstart = Calendar.getInstance();
                File file = new File("D:/1_1_1_1_1_0.json");
                if (!file.exists())
                    file.createNewFile();
                FileOutputStream out = new FileOutputStream(file);
                System.out.println("开始写文件!");
                flag++;
                if(flag>2)
                    flag=flag-3;
                List<String> config = getAllConfig(flag);
                JSONArray datamap = DataAcquisition.getQueryDatamap(config);
                String jsonstring=datamap.toJSONString();
                System.out.println("文件内容:"+jsonstring);
                OutputStreamWriter writer = new OutputStreamWriter(out, "UTF-8");
                BufferedWriter bufferedWriter = new BufferedWriter(writer);
                bufferedWriter.write(jsonstring);
                bufferedWriter.flush();
                bufferedWriter.close();
                System.out.println("写文件结束!");
                Calendar calend = Calendar.getInstance();
                System.out.println("写文件共花了" + (calend.getTimeInMillis() - calstart.getTimeInMillis()) + "毫秒");
            } finally {
                lock.writeLock().unlock();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

}

读线程:

package testjzx.testjzx2;

import testjzx.Read2;

public class ThreadA extends Thread {
    private Service service;
    public ThreadA(Service service)
    {
        this.service=service;
    }
    public void run() {
        while (true) {
            try {
                service.read();
                sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

写线程

package testjzx.testjzx2;
public class ThreadB extends Thread{
    private Service service;
    public ThreadB(Service service)
    {
        this.service=service;
    }
    public void run() {
        while (true) {
            try {
                service.write();
                sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

线程级别的锁,在一个main函数开启两个线程即可

package testjzx.testjzx2;

public class Test {
    public static void main(String[] args)throws InterruptedException {
        Service service = new Service();
        ThreadA a = new ThreadA(service);
        a.setName("A");
        a.start();
        ThreadB b = new ThreadB(service);
        b.setName("B");
        b.start();
    }
}

猜你喜欢

转载自blog.csdn.net/qq_38765865/article/details/104699742
今日推荐