- 浏览: 984400 次
文章分类
- 全部博客 (428)
- Hadoop (2)
- HBase (1)
- ELK (1)
- ActiveMQ (13)
- Kafka (5)
- Redis (14)
- Dubbo (1)
- Memcached (5)
- Netty (56)
- Mina (34)
- NIO (51)
- JUC (53)
- Spring (13)
- Mybatis (17)
- MySQL (21)
- JDBC (12)
- C3P0 (5)
- Tomcat (13)
- SLF4J-log4j (9)
- P6Spy (4)
- Quartz (12)
- Zabbix (7)
- JAVA (9)
- Linux (15)
- HTML (9)
- Lucene (0)
- JS (2)
- WebService (1)
- Maven (4)
- Oracle&MSSQL (14)
- iText (11)
- Development Tools (8)
- UTILS (4)
- LIFE (8)
最新评论
-
Donald_Draper:
Donald_Draper 写道刘落落cici 写道能给我发一 ...
DatagramChannelImpl 解析三(多播) -
Donald_Draper:
刘落落cici 写道能给我发一份这个类的源码吗Datagram ...
DatagramChannelImpl 解析三(多播) -
lyfyouyun:
请问楼主,执行消息发送的时候,报错:Transport sch ...
ActiveMQ连接工厂、连接详解 -
ezlhq:
关于 PollArrayWrapper 状态含义猜测:参考 S ...
WindowsSelectorImpl解析一(FdMap,PollArrayWrapper) -
flyfeifei66:
打算使用xmemcache作为memcache的客户端,由于x ...
Memcached分布式客户端(Xmemcached)
文件通道解析一(读写操作,通道数据传输等):http://donald-draper.iteye.com/blog/2374603
引言:
上一篇文章看了文件通道,读写操作,通道数据传输操作,先来回顾一下:
文件通道的构造,主要是初始化通道读写模式,追加模式append及文件分发器,FileDispatcherImpl。
文件通道的读写操作的实际操作都是由IOUtil协助FileDispatcherImpl完成,这一点和SocketChannel通道读写思路基本相同。
文件通道传输方法transferTo,首先确保当前文件通道是否打开,是否可读,然后检查目的通道是否关闭,是否可写;然后先调用文件通道本地方法传输通道的数据到目的通道,如果失败,则将文件通道数据,映射到内存MappedByteBuffer,然后调用目的通道的写操作(MappedByteBuffer),如果再失败,则将通道数据,写到DirectByteBuffer中,然后在调用目的通道的写操作(DirectByteBuffer)。
文件通道传输方法transferFrom,确保当前通道可写,打开,源通道可读打开,如果源通道为文件通道,将源通道数据映射的内存MappedByteBuffer,然后由IOUtil协助FileDispatcherImpl,将MappedByteBuffer
写入当前通道,如果源通道非文件通道,则先调用源通道的读操作,从源通道读取数据,写到临时DirectByteBuffer,委托write,写DirectByteBuffer到当前通道,即由IOUtil协助FileDispatcherImpl,将DirectByteBuffer写入当前通道。
在往下看之前我们先把文件通道的相关filed贴出,以便我们理解:
现在我们来文件的lock和trylock方法
再来看锁文件region方法:
//尝试加锁
从lock方法和try方法来看,首先检查共享模式参数shared与当前通道的读写模式是否匹配,然后根具postion,size和shared信息构造文件锁FileLockImpl,添加到通道文件锁表filelocktable中,再通过文件分发器FileDispatcherImpl锁文件region,如果成功,则创建新的文件锁替换旧的文件锁。如果lock失败,则从通道文件锁表filelocktable移除先前添加的文件锁。这里为什么要先创建文件锁添加到通道文件锁表filelocktable中,可能是为了先抢占通道文件锁表的位置,再去通FileDispatcherImpl锁文件region,成功则创建新的文件锁替换旧的文件锁。lock方法和trylock方法不同的是在FileDispatcherImpl锁文件region这个过程,lock为循环文件region,直到成功,而trylock方法,只锁一次,成功则则创建新的文件锁替换旧的文件锁,失败则从通道文件锁表filelocktable移除先前添加的文件锁,返回。
lock方法和trylock方法我们几点要关注:
1.
2.
3.
下面分别来看这几点:
1.
//FileLockImpl
//FileLock
2.
从上面可以看出如果为通道文件锁表为共享模式,则创建SharedFileLockTable,否则为
SimpleFileLockTable;
上述方法中break MISSING_BLOCK_LABEL_73类似的语句,这就由于反编译错误导致的,break语句有两种,一种为平时我们用的无label的break,即在for或while,switch语句中直接break;,break还有一种方式为break Label;即跳出循环到指定的Label:
实例:
由于反编译插件无法识别这样的语句,所以出现break MISSING_BLOCK_LABEL_73类似的语句。
Branching Statements-The break Statement:http://docs.oracle.com/javase/tutorial/java/nutsandbolts/branch.html
Dealing with labels in decompiled code:http://stackoverflow.com/questions/6347930/dealing-with-labels-in-decompiled-code
我们先看一下FileLockTable的定义
再来看SimpleFileLockTable
//FileChannelImpl-SimpleFileLockTable
再来看SharedFileLockTable
SharedFileLockTable用于存储文件共享锁,SimpleFileLockTable用于存储文件互质锁;
两者最大的不同是SimpleFileLockTable用list去管理文件锁,而SharedFileLockTable
用于ConcurrentHashMap管理文件锁。
3.
//FileDispatcherImpl
来看释放文件锁
来看这一句:
//FileDispatcherImpl
//获取文件锁table共享模式
再来看关闭通道
//FileDispatcherImpl
总结:
lock方法和try方法,首先检查共享模式参数shared与当前通道的读写模式是否匹配,然后根据具postion,size和shared信息构造文件锁FileLockImpl,添加到通道文件锁表filelocktable中,再通过文件分发器FileDispatcherImpl锁文件region,如果成功,则创建新的文件锁替换旧的文件锁。如果lock失败,则从通道文件锁表filelocktable移除先前添加的文件锁。这里为什么要先创建文件锁添加到通道文件锁表filelocktable中,可能是为了先抢占通道文件锁表的位置,再去通FileDispatcherImpl锁文件region,成功则创建新的文件锁替换旧的文件锁。lock方法和trylock方法不同的是在FileDispatcherImpl锁文件region这个过程,lock为循环文件region,直到成功,而trylock方法,只锁一次,成功则则创建新的文件锁替换旧的文件锁,失败则从通道文件锁表filelocktable移除先前添加的文件锁,返回。
附:
引言:
上一篇文章看了文件通道,读写操作,通道数据传输操作,先来回顾一下:
文件通道的构造,主要是初始化通道读写模式,追加模式append及文件分发器,FileDispatcherImpl。
文件通道的读写操作的实际操作都是由IOUtil协助FileDispatcherImpl完成,这一点和SocketChannel通道读写思路基本相同。
文件通道传输方法transferTo,首先确保当前文件通道是否打开,是否可读,然后检查目的通道是否关闭,是否可写;然后先调用文件通道本地方法传输通道的数据到目的通道,如果失败,则将文件通道数据,映射到内存MappedByteBuffer,然后调用目的通道的写操作(MappedByteBuffer),如果再失败,则将通道数据,写到DirectByteBuffer中,然后在调用目的通道的写操作(DirectByteBuffer)。
文件通道传输方法transferFrom,确保当前通道可写,打开,源通道可读打开,如果源通道为文件通道,将源通道数据映射的内存MappedByteBuffer,然后由IOUtil协助FileDispatcherImpl,将MappedByteBuffer
写入当前通道,如果源通道非文件通道,则先调用源通道的读操作,从源通道读取数据,写到临时DirectByteBuffer,委托write,写DirectByteBuffer到当前通道,即由IOUtil协助FileDispatcherImpl,将DirectByteBuffer写入当前通道。
在往下看之前我们先把文件通道的相关filed贴出,以便我们理解:
public class FileChannelImpl extends FileChannel { private static final long allocationGranularity = initIDs(); private final FileDispatcher nd;//文件分发器 private final FileDescriptor fd;//文件描述 private final boolean writable;//通道是否可写 private final boolean readable;//通道是否可读 private final boolean append;//通道写是否为追加模式 private final Object parent;//创建通道的对象 //下面这些属性,暂时不能确定是具体什么意思,只能先从字面上去理解, //这里我们先放在这里,后面用到在讲 private final NativeThreadSet threads = new NativeThreadSet(2); private final Object positionLock = new Object();//文件读写是位置锁 private static volatile boolean transferSupported = true;//是否支持通道传输 private static volatile boolean pipeSupported = true;//是否支持管道 private static volatile boolean fileSupported = true;//是否支持文件 private static final long MAPPED_TRANSFER_SIZE = 8388608L;/ private static final int TRANSFER_SIZE = 8192; private static final int MAP_RO = 0; private static final int MAP_RW = 1; private static final int MAP_PV = 2; private volatile FileLockTable fileLockTable;//存放文件锁的Table private static boolean isSharedFileLockTable;//文件锁table是否为共享 private static volatile boolean propertyChecked; static final boolean $assertionsDisabled = !sun/nio/ch/FileChannelImpl.desiredAssertionStatus(); static { //加载nio,net资源库 Util.load(); } private static native long initIDs(); }
现在我们来文件的lock和trylock方法
再来看锁文件region方法:
public FileLock lock(long l, long l1, boolean flag) throws IOException { FileLockImpl filelockimpl; FileLockTable filelocktable; boolean flag1; int i; ensureOpen(); if(flag && !readable)//如果写模式,锁不能为共享模式 throw new NonReadableChannelException(); if(!flag && !writable)//如果为读模,则锁必须共享模式 throw new NonWritableChannelException(); //创建文件锁 filelockimpl = new FileLockImpl(this, l, l1, flag); //获取文件通道的文件锁table filelocktable = fileLockTable(); //将文件锁,加入通道文件锁table中 filelocktable.add(filelockimpl); flag1 = false; i = -1; FileLock filelock; begin(); ... int j; //不断的尝试加锁,直到成功 do //尝试锁文件region j = nd.lock(fd, true, l, l1, flag); while(j == 2 && isOpen()); if(isOpen()) { if(j == 1) { if(!$assertionsDisabled && !flag) throw new AssertionError(); //创建新的文件锁 FileLockImpl filelockimpl1 = new FileLockImpl(this, l, l1, false); //替换filelocktable旧的文件锁 filelocktable.replace(filelockimpl, filelockimpl1); filelockimpl = filelockimpl1; } flag1 = true; } 如果锁文件region失败,则从filelocktable移除 if(!flag1) filelocktable.remove(filelockimpl); threads.remove(i); try { end(flag1); } catch(ClosedByInterruptException closedbyinterruptexception) { throw new FileLockInterruptionException(); } ... return filelockimpl; }
//尝试加锁
public FileLock tryLock(long l, long l1, boolean flag) throws IOException { FileLockImpl filelockimpl; FileLockTable filelocktable; int j; ensureOpen(); if(flag && !readable)//如果写模式,锁不能为共享模式 throw new NonReadableChannelException(); if(!flag && !writable)//如果为读模,则锁必须共享模式 throw new NonWritableChannelException(); //创建文件锁 filelockimpl = new FileLockImpl(this, l, l1, flag); filelocktable = fileLockTable();//获取文件通道的文件锁table filelocktable.add(filelockimpl);//将文件锁,加入通道文件锁table中 j = threads.add(); int i; Object obj; try { ensureOpen(); //尝试锁文件region i = nd.lock(fd, false, l, l1, flag); } catch(IOException ioexception) { filelocktable.remove(filelockimpl); throw ioexception; } ... //创建新的文件锁 obj = new FileLockImpl(this, l, l1, false); //替换filelocktable旧的文件锁 filelocktable.replace(filelockimpl, ((FileLock) (obj))); filelockimpl1 = ((FileLockImpl) (obj)); threads.remove(j); return filelockimpl1; ... }
从lock方法和try方法来看,首先检查共享模式参数shared与当前通道的读写模式是否匹配,然后根具postion,size和shared信息构造文件锁FileLockImpl,添加到通道文件锁表filelocktable中,再通过文件分发器FileDispatcherImpl锁文件region,如果成功,则创建新的文件锁替换旧的文件锁。如果lock失败,则从通道文件锁表filelocktable移除先前添加的文件锁。这里为什么要先创建文件锁添加到通道文件锁表filelocktable中,可能是为了先抢占通道文件锁表的位置,再去通FileDispatcherImpl锁文件region,成功则创建新的文件锁替换旧的文件锁。lock方法和trylock方法不同的是在FileDispatcherImpl锁文件region这个过程,lock为循环文件region,直到成功,而trylock方法,只锁一次,成功则则创建新的文件锁替换旧的文件锁,失败则从通道文件锁表filelocktable移除先前添加的文件锁,返回。
lock方法和trylock方法我们几点要关注:
1.
//创建文件锁 filelockimpl = new FileLockImpl(this, l, l1, flag);
2.
filelocktable = fileLockTable();//获取文件通道的文件锁table
3.
j = nd.lock(fd, true, l, l1, flag);
下面分别来看这几点:
1.
//创建文件锁 filelockimpl = new FileLockImpl(this, l, l1, flag);
//FileLockImpl
public class FileLockImpl extends FileLock { private volatile boolean valid;//有效性标志 static final boolean $assertionsDisabled = !sun/nio/ch/FileLockImpl.desiredAssertionStatus(); //构造 FileLockImpl(FileChannel filechannel, long l, long l1, boolean flag) { super(filechannel, l, l1, flag); valid = true;//初始化有效 } FileLockImpl(AsynchronousFileChannel asynchronousfilechannel, long l, long l1, boolean flag) { super(asynchronousfilechannel, l, l1, flag); valid = true; } //判断文件锁是否有效 public boolean isValid() { return valid; } //使文件锁无效 void invalidate() { //如果断言开启,断言线程是否持有锁 if(!$assertionsDisabled && !Thread.holdsLock(this)) { throw new AssertionError(); } else { valid = false; return; } } //释放文件锁 public synchronized void release() throws IOException { //获取锁关联的通道 Channel channel = acquiredBy(); if(!channel.isOpen())//通道关闭 throw new ClosedChannelException(); if(valid)//在通道有效的情况下 { if(channel instanceof FileChannelImpl) //将实际工作委托相应的通道 ((FileChannelImpl)channel).release(this); else if(channel instanceof AsynchronousFileChannelImpl) ((AsynchronousFileChannelImpl)channel).release(this); else throw new AssertionError(); valid = false; } } }
//FileLock
public abstract class FileLock implements AutoCloseable { private final Channel channel;//锁关联通道 private final long position;//文件锁region的起始位置 private final long size;//region大小 private final boolean shared;//是否为共享模式 //构造文件锁 protected FileLock(FileChannel channel, long position, long size, boolean shared) { if (position < 0) throw new IllegalArgumentException("Negative position"); if (size < 0) throw new IllegalArgumentException("Negative size"); if (position + size < 0) throw new IllegalArgumentException("Negative position + size"); this.channel = channel; this.position = position; this.size = size; this.shared = shared; } /** * Returns the file channel upon whose file this lock was acquired. *返回用有本文件锁的通道 * This method has been superseded by the {@link #acquiredBy acquiredBy} * method. * * @return The file channel, or {@code null} if the file lock was not * acquired by a file channel. */ public final FileChannel channel() { return (channel instanceof FileChannel) ? (FileChannel)channel : null; } /** * Returns the channel upon whose file this lock was acquired. *//获取锁关联通道 * @return The channel upon whose file this lock was acquired. * * @since 1.7 */ public Channel acquiredBy() { return channel; } /** * Returns the position within the file of the first byte of the locked * region. *获取锁文件region的起始position * A locked region need not be contained within, or even overlap, the * actual underlying file, so the value returned by this method may exceed * the file's current size. * * @return The position */ public final long position() { return position; } /** * Returns the size of the locked region in bytes. *获取锁文件region的size * A locked region need not be contained within, or even overlap, the * actual underlying file, so the value returned by this method may exceed * the file's current size. * * @return The size of the locked region */ public final long size() { return size; } /** * Tells whether this lock is shared. *判断锁是否为共享模式 * @return <tt>true</tt> if lock is shared, * <tt>false</tt> if it is exclusive */ public final boolean isShared() { return shared; } /** * Tells whether or not this lock overlaps the given lock range. </p> *//判断加锁的文件region是否重叠 * @return <tt>true</tt> if, and only if, this lock and the given lock * range overlap by at least one byte */ public final boolean overlaps(long position, long size) { if (position + size <= this.position) return false; // That is below this if (this.position + this.size <= position) return false; // This is below that return true; } /** * Tells whether or not this lock is valid. *判断锁是否有效 * A lock object remains valid until it is released or the associated * file channel is closed, whichever comes first. * * @return <tt>true</tt> if, and only if, this lock is valid */ public abstract boolean isValid(); /** * Releases this lock. * * If this lock object is valid then invoking this method releases the * lock and renders the object invalid. If this lock object is invalid * then invoking this method has no effect. *释放锁 * @throws ClosedChannelException * If the channel that was used to acquire this lock * is no longer open * * @throws IOException * If an I/O error occurs */ public abstract void release() throws IOException; /** * This method invokes the {@link #release} method. It was added * to the class so that it could be used in conjunction with the * automatic resource management block construct. *关闭文件锁 * @since 1.7 */ public final void close() throws IOException { release(); } }
2.
filelocktable = fileLockTable();//获取文件通道的文件锁table
//获取文件通道的文件锁table private FileLockTable fileLockTable() throws IOException { if(fileLockTable != null) break MISSING_BLOCK_LABEL_96; FileChannelImpl filechannelimpl = this; JVM INSTR monitorenter ; int i; if(fileLockTable != null) break MISSING_BLOCK_LABEL_84; if(!isSharedFileLockTable()) break MISSING_BLOCK_LABEL_73; i = threads.add(); ensureOpen(); //如果为共享模式 fileLockTable = FileLockTable.newSharedFileLockTable(this, fd); threads.remove(i); break MISSING_BLOCK_LABEL_84; Exception exception; exception; threads.remove(i); throw exception; //否则 fileLockTable = new SimpleFileLockTable(); break MISSING_BLOCK_LABEL_96; Exception exception1; exception1; throw exception1; return fileLockTable; }
从上面可以看出如果为通道文件锁表为共享模式,则创建SharedFileLockTable,否则为
SimpleFileLockTable;
上述方法中break MISSING_BLOCK_LABEL_73类似的语句,这就由于反编译错误导致的,break语句有两种,一种为平时我们用的无label的break,即在for或while,switch语句中直接break;,break还有一种方式为break Label;即跳出循环到指定的Label:
实例:
testLable: for (obj : list){ if (flag) break testLable; }
由于反编译插件无法识别这样的语句,所以出现break MISSING_BLOCK_LABEL_73类似的语句。
Branching Statements-The break Statement:http://docs.oracle.com/javase/tutorial/java/nutsandbolts/branch.html
Dealing with labels in decompiled code:http://stackoverflow.com/questions/6347930/dealing-with-labels-in-decompiled-code
我们先看一下FileLockTable的定义
abstract class FileLockTable { protected FileLockTable() { } //创建共享文件锁表 public static FileLockTable newSharedFileLockTable(Channel channel, FileDescriptor filedescriptor) throws IOException { return new SharedFileLockTable(channel, filedescriptor); } public abstract void add(FileLock filelock)//添加 throws OverlappingFileLockException; public abstract void remove(FileLock filelock);//移除 public abstract List removeAll();//移除所有 public abstract void replace(FileLock filelock, FileLock filelock1);//替换 }
再来看SimpleFileLockTable
//FileChannelImpl-SimpleFileLockTable
private static class SimpleFileLockTable extends FileLockTable { private final List lockList = new ArrayList(2);//文件锁集合 static final boolean $assertionsDisabled = !sun/nio/ch/FileChannelImpl.desiredAssertionStatus(); public SimpleFileLockTable() { } //添加文件锁 public void add(FileLock filelock) throws OverlappingFileLockException { synchronized(lockList) { checkList(filelock.position(), filelock.size()); lockList.add(filelock); } } //查看添加的文件锁,是否与文件锁集合中,已经加锁的文件region重叠 private void checkList(long l, long l1) throws OverlappingFileLockException { //如果断言开启,当前线程不只有文件锁集合,则抛出AssertionError if(!$assertionsDisabled && !Thread.holdsLock(lockList)) throw new AssertionError(); //遍历当前文件锁集合,查看添加的文件锁,是否与已经加锁的文件region重叠, //重叠则抛出OverlappingFileLockException for(Iterator iterator = lockList.iterator(); iterator.hasNext();) { FileLock filelock = (FileLock)iterator.next(); if(filelock.overlaps(l, l1)) throw new OverlappingFileLockException(); } } //移除文件锁 public void remove(FileLock filelock) { synchronized(lockList) { lockList.remove(filelock); } } //移除所有文件锁 public List removeAll() { List list = lockList; JVM INSTR monitorenter ; ArrayList arraylist; arraylist = new ArrayList(lockList); lockList.clear();//直接clear文件锁集合 return arraylist; Exception exception; exception; throw exception; } //替换文件锁,先移除filelock,后添加filelock1 public void replace(FileLock filelock, FileLock filelock1) { synchronized(lockList) { lockList.remove(filelock); lockList.add(filelock1); } } }
再来看SharedFileLockTable
class SharedFileLockTable extends FileLockTable { private static ConcurrentHashMap lockMap = new ConcurrentHashMap();//文件锁Map private static ReferenceQueue queue = new ReferenceQueue(); private final Channel channel;//关联通道 private final FileKey fileKey;//文件锁key static final boolean $assertionsDisabled = !sun/nio/ch/SharedFileLockTable.desiredAssertionStatus(); //文件锁引用 private static class FileLockReference extends WeakReference { FileKey fileKey() { return fileKey; } private FileKey fileKey; FileLockReference(FileLock filelock, ReferenceQueue referencequeue, FileKey filekey) { super(filelock, referencequeue); fileKey = filekey; } } //构造共享文件锁table SharedFileLockTable(Channel channel1, FileDescriptor filedescriptor) throws IOException { channel = channel1; //创建文件key fileKey = FileKey.create(filedescriptor); } //添加文件锁 public void add(FileLock filelock) throws OverlappingFileLockException { //从文件锁Map获取,文件key对应的锁集合 Object obj = (List)lockMap.get(fileKey); _L3: List list; label0: { if(obj != null) break MISSING_BLOCK_LABEL_95; //文件锁集合为null,则创建共享锁集合 obj = new ArrayList(2); synchronized(obj) { //将文件key与文件锁集合放入Map中 list = (List)lockMap.putIfAbsent(fileKey, obj); if(list != null) break label0; //将文件锁索引添加到锁集合中 ((List) (obj)).add(new FileLockReference(filelock, queue, fileKey)); } break; /* Loop/switch isn't completed */ } obj2; JVM INSTR monitorexit ; goto _L1 exception; throw exception; _L1: obj = list; List list1; label1: { synchronized(obj) { list1 = (List)lockMap.get(fileKey); if(obj != list1) break label1; checkList(((List) (obj)), filelock.position(), filelock.size()); ((List) (obj)).add(new FileLockReference(filelock, queue, fileKey)); } break; /* Loop/switch isn't completed */ } obj = list1; obj1; JVM INSTR monitorexit ; if(true) goto _L3; else goto _L2 exception1; throw exception1; _L2: removeStaleEntries(); return; } //如果文件key对应的,文件锁集合为空,则从map中移除文件key Entry private void removeKeyIfEmpty(FileKey filekey, List list) { if(!$assertionsDisabled && !Thread.holdsLock(list)) throw new AssertionError(); if(!$assertionsDisabled && lockMap.get(filekey) != list) throw new AssertionError(); if(list.isEmpty()) lockMap.remove(filekey); } //移除文件锁 public void remove(FileLock filelock) { if(!$assertionsDisabled && filelock == null) throw new AssertionError(); //从锁Map中获取文件key对应的集合 List list = (List)lockMap.get(fileKey); if(list == null) return; synchronized(list) { int i = 0; do { if(i >= list.size()) break; //获取文件锁引用 FileLockReference filelockreference = (FileLockReference)list.get(i); //参文件锁引用获取文件锁 FileLock filelock1 = (FileLock)filelockreference.get(); if(filelock1 == filelock) { if(!$assertionsDisabled && (filelock1 == null || filelock1.acquiredBy() != channel)) throw new AssertionError(); //找到,则清除引用,help GC filelockreference.clear(); list.remove(i);//从文件锁集合中移除 break; } i++; } while(true); } } //移除所有文件锁 public List removeAll() { ArrayList arraylist = new ArrayList(); //获取文件key的文件锁集合 List list = (List)lockMap.get(fileKey); if(list != null) synchronized(list) { //遍历锁集合,将通读文件的文件锁添加到arraylist for(int i = 0; i < list.size();) { FileLockReference filelockreference = (FileLockReference)list.get(i); FileLock filelock = (FileLock)filelockreference.get(); if(filelock != null && filelock.acquiredBy() == channel) { filelockreference.clear(); list.remove(i); arraylist.add(filelock); } else { i++; } } //移除文件key的锁集合 removeKeyIfEmpty(fileKey, list); } return arraylist; } //替换文件锁 public void replace(FileLock filelock, FileLock filelock1) { //获取文件锁集合 List list = (List)lockMap.get(fileKey); if(!$assertionsDisabled && list == null) throw new AssertionError(); synchronized(list) { int i = 0; do { if(i >= list.size()) break; FileLockReference filelockreference = (FileLockReference)list.get(i); FileLock filelock2 = (FileLock)filelockreference.get(); if(filelock2 == filelock) { //找到对应的文件锁,则清除引用,help gc filelockreference.clear(); list.set(i, new FileLockReference(filelock1, queue, fileKey));//替换文件锁引用 break; } i++; } while(true); } } //检查文件key的锁集中的文件锁,锁住文件的region是否重叠 private void checkList(List list, long l, long l1) throws OverlappingFileLockException { if(!$assertionsDisabled && !Thread.holdsLock(list)) throw new AssertionError(); for(Iterator iterator = list.iterator(); iterator.hasNext();) { FileLockReference filelockreference = (FileLockReference)iterator.next(); FileLock filelock = (FileLock)filelockreference.get(); if(filelock != null && filelock.overlaps(l, l1)) throw new OverlappingFileLockException(); } } //清空文件锁Map private void removeStaleEntries() { do { FileLockReference filelockreference; //从引用队列中取出文件锁引用 if((filelockreference = (FileLockReference)queue.poll()) == null) break; //从文件锁引用获取文件key FileKey filekey = filelockreference.fileKey(); //获取文件key对应的文件锁 List list = (List)lockMap.get(filekey); if(list != null) synchronized(list) { list.remove(filelockreference); //移除文件key对应的文件锁集合 removeKeyIfEmpty(filekey, list); } } while(true); } }
SharedFileLockTable用于存储文件共享锁,SimpleFileLockTable用于存储文件互质锁;
两者最大的不同是SimpleFileLockTable用list去管理文件锁,而SharedFileLockTable
用于ConcurrentHashMap管理文件锁。
3.
j = nd.lock(fd, true, l, l1, flag);
//FileDispatcherImpl
int lock(FileDescriptor filedescriptor, boolean flag, long l, long l1, boolean flag1) throws IOException { return lock0(filedescriptor, flag, l, l1, flag1); } static native int lock0(FileDescriptor filedescriptor, boolean flag, long l, long l1, boolean flag1) throws IOException;
来看释放文件锁
void release(FileLockImpl filelockimpl) throws IOException { int i = threads.add(); ensureOpen(); //文件分发器先释放锁住的文件region nd.release(fd, filelockimpl.position(), filelockimpl.size()); ... if(!$assertionsDisabled && fileLockTable == null) { throw new AssertionError(); } else { //从文件锁table中移除文件锁 fileLockTable.remove(filelockimpl); return; } }
来看这一句:
//文件分发器先释放锁住的文件region nd.release(fd, filelockimpl.position(), filelockimpl.size());
//FileDispatcherImpl
void release(FileDescriptor filedescriptor, long l, long l1) throws IOException { release0(filedescriptor, l, l1); } static native void release0(FileDescriptor filedescriptor, long l, long l1) throws IOException
//获取文件锁table共享模式
private static boolean isSharedFileLockTable() { if(!propertyChecked) synchronized(sun/nio/ch/FileChannelImpl) { if(!propertyChecked) { String s = (String)AccessController.doPrivileged(new GetPropertyAction("sun.nio.ch.disableSystemWideOverlappingFileLockCheck")); isSharedFileLockTable = s == null || s.equals("false"); propertyChecked = true; } } return isSharedFileLockTable; }
再来看关闭通道
protected void implCloseChannel() throws IOException { if(fileLockTable != null) { //清空文件锁table for(Iterator iterator = fileLockTable.removeAll().iterator(); iterator.hasNext();) { FileLock filelock = (FileLock)iterator.next(); synchronized(filelock) { if(filelock.isValid()) { //释放文件锁,锁住的文件region nd.release(fd, filelock.position(), filelock.size()); ((FileLockImpl)filelock).invalidate();//使文件锁无效 } } } } //预先关闭文件描述 nd.preClose(fd); threads.signalAndWait(); //如果父对象不为null,则关闭父对象,否则关闭文件分发器 if(parent != null) ((Closeable)parent).close(); else nd.close(fd); }
//FileDispatcherImpl
void close(FileDescriptor filedescriptor) throws IOException { close0(filedescriptor); } static native void close0(FileDescriptor filedescriptor) throws IOException;
总结:
lock方法和try方法,首先检查共享模式参数shared与当前通道的读写模式是否匹配,然后根据具postion,size和shared信息构造文件锁FileLockImpl,添加到通道文件锁表filelocktable中,再通过文件分发器FileDispatcherImpl锁文件region,如果成功,则创建新的文件锁替换旧的文件锁。如果lock失败,则从通道文件锁表filelocktable移除先前添加的文件锁。这里为什么要先创建文件锁添加到通道文件锁表filelocktable中,可能是为了先抢占通道文件锁表的位置,再去通FileDispatcherImpl锁文件region,成功则创建新的文件锁替换旧的文件锁。lock方法和trylock方法不同的是在FileDispatcherImpl锁文件region这个过程,lock为循环文件region,直到成功,而trylock方法,只锁一次,成功则则创建新的文件锁替换旧的文件锁,失败则从通道文件锁表filelocktable移除先前添加的文件锁,返回。
附:
public class FileKey { private static native void initIDs(); private long dwVolumeSerialNumber; private long nFileIndexHigh; private long nFileIndexLow; static { initIDs(); } private FileKey() { } public static FileKey create(FileDescriptor filedescriptor) { FileKey filekey = new FileKey(); try { filekey.init(filedescriptor); } catch(IOException ioexception) { throw new Error(ioexception); } return filekey; } private native void init(FileDescriptor filedescriptor) throws IOException; public int hashCode() { return (int)(dwVolumeSerialNumber ^ dwVolumeSerialNumber >>> 32) + (int)(nFileIndexHigh ^ nFileIndexHigh >>> 32) + (int)(nFileIndexLow ^ nFileIndexHigh >>> 32); } public boolean equals(Object obj) { if(obj == this) return true; if(!(obj instanceof FileKey)) return false; FileKey filekey = (FileKey)obj; return dwVolumeSerialNumber == filekey.dwVolumeSerialNumber && nFileIndexHigh == filekey.nFileIndexHigh && nFileIndexLow == filekey.nFileIndexLow; } }
发表评论
-
文件通道解析一(读写操作,通道数据传输等)
2017-05-16 10:04 1172Reference定义(PhantomRefere ... -
文件通道创建方式综述
2017-05-15 17:39 1074Reference定义(PhantomReference,Cl ... -
文件读写方式简单综述后续(文件,流构造)
2017-05-14 23:04 1493Java Socket通信实例:http://donald-d ... -
文件读写方式简单综述
2017-05-14 11:13 1142Java Socket通信实例:http://donald-d ... -
FileChanne定义
2017-05-12 23:28 947文件读写方式简单综述:http://donald-draper ... -
SeekableByteChannel接口定义
2017-05-11 08:43 1244ByteChannel,分散聚集通道接口的定义(SocketC ... -
FileChannel示例
2017-05-11 08:37 1003前面我们看过socket通道,datagram通道,以管道Pi ... -
PipeImpl解析
2017-05-11 08:41 941ServerSocketChannel定义:http://do ... -
Pipe定义
2017-05-10 09:07 916Channel接口定义:http://donald-drape ... -
NIO-Pipe示例
2017-05-10 08:47 914PipeImpl解析:http://donald-draper ... -
DatagramChannelImpl 解析四(地址绑定,关闭通道等)
2017-05-10 08:27 790DatagramChannelImpl 解析一(初始化):ht ... -
DatagramChannelImpl 解析三(多播)
2017-05-10 08:20 1926DatagramChannelImpl 解析一(初始化):ht ... -
NIO-UDP实例
2017-05-09 12:32 1592DatagramChannelImpl 解析一(初始化):ht ... -
DatagramChannelImpl 解析二(报文发送与接收)
2017-05-09 09:03 1418DatagramChannelImpl 解析一(初始化):ht ... -
DatagramChannelImpl 解析一(初始化)
2017-05-08 21:52 1421Channel接口定义:http://donald-drape ... -
MembershipKeyImpl 简介
2017-05-08 09:11 931MembershipKey定义:http://donald-d ... -
DatagramChannel定义
2017-05-07 23:13 1238Channel接口定义:http://donald-drape ... -
MulticastChanne接口定义
2017-05-07 13:45 1146NetworkChannel接口定义:ht ... -
MembershipKey定义
2017-05-06 16:20 927package java.nio.channels; i ... -
SocketChannelImpl 解析四(关闭通道等)
2017-05-05 08:38 2549SocketChannelImpl 解析一(通道连接,发送数据 ...
相关推荐
它选择合适的射频通道进行通信,检测和解析空中数据包,控制数据的发送时机,确保数据的完整性和可靠性,处理ACK确认及重传机制,并管理链路状态。此外,LL层还支持多连接,例如Nordic的BLE协议栈可同时支持20个连接...
finally块保证了即使在异常情况下,某些代码也能被执行,如关闭文件流或网络连接。理解并合理使用Checked和Unchecked异常是关键。 4. **JVM调优** - 面试陷阱:面试官可能会要求解释JVM的内存模型,或者如何设置...
在实现过程中,开发者可能会遇到诸如内存管理、网络异常、文件锁等问题,需要通过编写健壮的代码来解决。通过这个项目,你可以深入理解网络编程的基本原理,以及FTP协议的工作机制。 在压缩包中的"C语言实现FTP...
还有日志分析工具,它们能够解析应用的日志文件,找出潜在的问题线索。 此外,还有一些专门针对并发和共享资源管理的工具,如Java的VisualVM、Python的Multiprocessing库的debug模式,以及各种分布式系统的监控框架...
本压缩包文件“行业分类-设备装置-电动推闩式逃生锁.zip”包含了一份详细的技术资料——“电动推闩式逃生锁.pdf”,以下将对其中的知识点进行深入解析。 首先,电动推闩式逃生锁的核心功能是提供一种自动或手动开启...
关闭IDE通道检测.bat 列举进程.bat 判断光驱是否可用.bat 判断光驱里有无光盘.bat 判断分区格式.bat 刷新策略.bat 取得硬盘数.bat 右键添加bat.bat 右键添加打开MS-DOS.bat 弹出光驱.bat 改变我的文档路径.bat 显示...
- **文件打开与关闭**:open、close等函数的使用方法及其注意事项。 - **文件读写操作**:read、write函数的基本用法以及高级功能,如非阻塞I/O、异步I/O等。 #### 5. 网络编程 - **套接字编程基础**:介绍socket...
- **多路复用Socket(NIO.2)**:Java 7扩展了非阻塞I/O,引入了新的File API,提供了异步文件操作,支持文件通道和文件锁,使得文件操作更加高效。 - **改进的字符串操作**:如`String`类新增了`join()`方法,用于...
以下是基于提供的文件内容,对消防安全管理制度的详细解析: 1. 消防安全教育、培训制度: - 定期举办消防知识宣传活动,通过宣传栏和知识竞赛提升员工的消防安全意识。 - 组织员工学习消防法规和规章制度,使...
`open()`, `close()`, `read()`, `write()`等函数用于文件的打开、关闭、读写。同时,还有`lseek()`用于设置文件指针位置,`chmod()`用于改变文件权限,`unlink()`用于删除文件。 4. **多线程编程**:Linux支持...
11. OS error code 11: Resource temporarily unavailable - 资源暂时不可用,如网络连接超时或文件锁。 12. OS error code 12: Cannot allocate memory - 内存分配失败,系统内存不足。 13. OS error code 13: ...
- 营业或工作期间,安全出口不得上锁,疏散指示标志不得被遮挡或关闭。 4. 消防控制中心管理制度: - 消防控制中心的操作员应熟悉各种消防设施的性能,确保应急时能快速、有序地操作。 - 认真记录消防值班情况,...
- **含义**:使用的文件描述符无效或已关闭。 #### 48. ENOEXEC (8) - **错误描述**:执行格式错误。 - **含义**:加载或执行的文件格式不被系统识别或支持。 #### 49. E2BIG (7) - **错误描述**:参数列表过...
在给定的压缩包文件中,包含了一系列与系统维护和优化相关的批处理脚本,让我们逐一解析这些脚本可能涉及的知识点。 1. XP开机优化.bat:这个批处理文件可能是用于优化Windows XP系统的启动过程,包括禁用不必要的...
关闭IDE通道检测.bat 分离路径和文件名.cmd 列举水产品最高&最低价记录.cmd 列举进程.bat 创建url格式的快捷方式.cmd 删除N天之前的文件.cmd 删除当前目录下及其子文件夹中所有的空文件夹.cmd 删除所有以数字命名的...
11. **NIO.2**:Java SE7扩展了非阻塞I/O(NIO),提供了文件系统路径、异步I/O操作和文件通道等新功能,增强了I/O性能。 12. **动态语言支持**:JDK 7增加了对动态语言的支持,如JSR 292,使得JVM可以更好地运行如...
LPC2368提供了多个UART通道,通过库函数可以方便地管理这些通道,如`uart_open()`和`uart_close()`分别用于打开和关闭指定的UART通道。同时,为了防止数据冲突,还需要正确使用互斥锁等同步机制。 总结起来,...
- 文件操作:C语言提供了一系列的stdio函数,如fopen、fread、fwrite和fclose等,用于文件的打开、读取、写入和关闭。 2. **网络编程**: - 套接字(Sockets):是网络通信的基础,用于创建进程间的通信通道,...