24.序列化对象克隆及文件锁学习
1.序列化对象克隆
我们也许学习过如何clone一个对象,就是通过Object中的clone方法实现,但是我们必须知道,Object中的clone方法实现的是浅clone。
如果我们想要clone一个完整的对象,我们需要学习如何去实现,序列化对象就是一种比较简单的完全clone方式。
1.1 什么是序列化与对象克隆?
有时想得到对象的一个“复制品”,使得复制品的变化不会引起原对象实体变化,反之亦然。我们称这样的复制品为原对象的一个克隆对象(简称克隆)。
1.2 如何实现?
使用对象流很容易获取一个序列化对象的克隆,只需将该对象输出流指向目的地,然后将该目的地作为一个对象输入流的源,那么该对象输入流从源中读回的对象一定是原对象的一个克隆。简言之:
就是对象输入流通过对象的序列化信息得到当前对象的一个克隆。
当程序想以较快的速度得到一个对象克隆时,可以用对象流将对象的序列化信息写入内存。
1.3 实例展示
下面是对象克隆的例子
import java.io.*;
public class SerializableStudy {
public static void main(String[] args) {
TV changhong = new TV();
changhong.setName("长虹电视");
changhong.setPrice(5678);
File file = new File("television.txt");
try{
//定义文件字节输出流,源为television.txt
FileOutputStream fileOut = new FileOutputStream(file);
//定义对象字节输出流
ObjectOutputStream objectOut = new ObjectOutputStream(fileOut);
//将对象序列化信息写入源中
objectOut.writeObject(changhong);
//关闭对象输出流
objectOut.close();
//定义文件输入流,源为television.txt
FileInputStream fileIn = new FileInputStream(file);
//定义对象字节输入流
ObjectInputStream objectIn = new ObjectInputStream(fileIn);
//将源中的对象读出得到changhong的克隆
TV xinfei = (TV)objectIn.readObject();
objectIn.close();//关闭对象输入流
System.out.println("changhong的名字:"+changhong.getName());
System.out.println("changhong的价格:"+changhong.getPrice());
System.out.println("changhong clone 的名字:"+xinfei.getName());
System.out.println("changhong clone 的价格"+xinfei.getPrice());
}catch(ClassNotFoundException event){
System.out.println("不能读出对象");
}catch(IOException event){
event.printStackTrace();
}
}
}
/**
* 被克隆的对象必须实现标记接口Serializable
*/
class TV implements Serializable {
String name;
int price;
public void setName(String s){
name =s;
}
public void setPrice(int n){
price = n;
}
public String getName(){
return name;
}
public int getPrice(){
return price;
}
}
2.文件锁
在实际的应用中,经常会出现几个程序处理同一个文件的情况发生,比如同时更新或读取文件。
一般来说会造成冲突,java提供了文件锁功能,可以帮助解决这样的问题。
2.1.FileLock和FileChannel类
这两个类分别在java.nio和java.nio.channels包中。
输入,输出流读写文件时可以使用文件锁,以下结合RandomAccessFile类来说明文件锁的使用方法。
RandomAccessFile创建的流在读写文件时可以使用文件锁。只要不解除该锁,其他程序无法操作被锁定的文件。
2.2 使用文件锁的步骤
先使用RandomAccessFile流建立指向文件的流对象,该对象的读写属性必须是rw,例如:
RandomAccessFile input=new RandomAccessFile("Example.java","rw");
然后input流调用方法getChannel();获得一个连接到底层文件的FileChannel对象(信道),例如:
FileChannel channel = input.getChannel();
信道调用tryLock();或lock();方法获得一个FileLock(文件锁)对象,这一过程称作对文件加锁。
例如:
FileLock lock = channel.tryLock();
这一 过程有两个结果,要么成功,要么失败,如果失败了,我们需要进行重试获取锁,如果成功了,我们就可以对文件进行操作了。
对文件加锁之后,如果想读,写文件必须让FileLock对象调用release();释放文件锁。
例如:
lock.release();
2.3编程实例
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.nio.charset.StandardCharsets;
public class LockWriteFile extends Thread{
public void run(){
long start = System.currentTimeMillis();
//创建文件对象
File file = new File("test.txt");
try {
//如果文件不存在,创建之
if(!file.exists()){
if(file.createNewFile()){
System.out.println("创建成功!!");
}else {
System.out.println("创建失败!!");
}
}
//对该文件加锁
RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw");
FileChannel fileChannel=randomAccessFile.getChannel();
FileLock fileLock=null;
while(true){
try {
fileLock = fileChannel.tryLock();
break;
} catch (Exception e) {
System.out.println("有其他线程正在操作该文件,当前线程"+Thread.currentThread().getName()+"休眠1000毫秒");
sleep(1000);
}
}
for(int i=1;i<=1000;i++){
sleep(10);
StringBuffer sb=new StringBuffer();
sb.append("这是第"+i+"行对应的数据");
sb.append("\n");
randomAccessFile.write(sb.toString().getBytes(StandardCharsets.UTF_8));
}
//释放锁
fileLock.release();
//关闭信道
fileChannel.close();
//关闭流
randomAccessFile.close();
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程:"+Thread.currentThread().getName()+",写文件耗时: "+(System.currentTimeMillis()-start)+"毫秒");
}
}
测试程序:
public class LockWriteTest {
public static void main(String[] args) {
LockWriteFile writeFileThread = new LockWriteFile();
writeFileThread.setName("writeThread");
LockWriteFile writeFileThread2 = new LockWriteFile();
writeFileThread2.setName("writeThread2");
writeFileThread.start();
writeFileThread2.start();
}
}
代码地址:
Java基础学习/src/main/java/Progress/exa24 · 严家豆/Study - 码云 - 开源中国 (gitee.com)