1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.IOException;
23 import java.lang.management.ManagementFactory;
24 import java.nio.channels.FileChannel;
25 import java.nio.channels.FileLock;
26 import java.nio.file.FileStore;
27 import java.nio.file.Files;
28 import java.nio.file.Path;
29 import java.nio.file.Paths;
30 import java.nio.file.StandardOpenOption;
31 import java.util.concurrent.CountDownLatch;
32 import java.util.concurrent.atomic.AtomicInteger;
33
34
35
36
37
38
39
40
41
42 public class TestNioLock
43 {
44 private static final int EC_WON = 10;
45
46 private static final int EC_LOST = 20;
47
48 private static final int EC_FAILED = 30;
49
50 private static final int EC_ERROR = 100;
51
52 public static void main( String[] args ) throws IOException, InterruptedException
53 {
54 if ( args.length != 3 )
55 {
56 System.out.println( "TestNioLock <test|perform> <file> <sleepMs>" );
57 System.exit( EC_ERROR );
58 }
59
60 String mode = args[0];
61 Path path = Paths.get( args[1] ).toAbsolutePath();
62 Path latchFile = path.getParent().resolve( TestNioLock.class.getName() + ".latchFile" );
63
64 if ( Files.isDirectory( path ) )
65 {
66 System.out.println( "The <file> cannot be directory." );
67 System.exit( EC_ERROR );
68 }
69 if ( !Files.isRegularFile( latchFile ) )
70 {
71 Files.createFile( latchFile );
72 }
73
74 if ( "test".equals( mode ) )
75 {
76 System.out.println( "Testing file locking on" );
77 System.out.println(
78 " Java " + System.getProperty( "java.version" ) + ", " + System.getProperty( "java.vendor" ) );
79 System.out.println(
80 " OS " + System.getProperty( "os.name" ) + " " + System.getProperty( "os.version" ) + " "
81 + System.getProperty( "os.arch" ) );
82
83 FileStore fileStore = Files.getFileStore( path.getParent() );
84 System.out.println( " FS " + fileStore.name() + " " + fileStore.type() );
85 System.out.println();
86
87 AtomicInteger oneResult = new AtomicInteger( -1 );
88 AtomicInteger twoResult = new AtomicInteger( -1 );
89 CountDownLatch latch = new CountDownLatch( 2 );
90 String javaCmd = System.getProperty( "java.home" ) + "/bin/java";
91
92 try ( FileChannel latchChannel = FileChannel.open( latchFile, StandardOpenOption.READ,
93 StandardOpenOption.WRITE ) )
94 {
95 try ( FileLock latchLock = latchChannel.lock( 0L, 1L, false ) )
96 {
97 new Thread( () ->
98 {
99 try
100 {
101 oneResult.set( new ProcessBuilder( javaCmd, TestNioLock.class.getName(),
102 "perform", args[1], args[2] ).inheritIO().start().waitFor() );
103 }
104 catch ( Exception e )
105 {
106 oneResult.set( EC_FAILED );
107 }
108 finally
109 {
110 latch.countDown();
111 }
112 } ).start();
113 new Thread( () ->
114 {
115 try
116 {
117 twoResult.set( new ProcessBuilder( javaCmd, TestNioLock.class.getName(),
118 "perform", args[1], args[2] ).inheritIO().start().waitFor() );
119 }
120 catch ( Exception e )
121 {
122 twoResult.set( EC_FAILED );
123 }
124 finally
125 {
126 latch.countDown();
127 }
128 } ).start();
129
130 Thread.sleep( 1000 );
131 latchLock.release();
132 latch.await();
133 }
134 }
135
136
137 int oneExit = oneResult.get();
138 int twoExit = twoResult.get();
139 if ( ( oneExit == EC_WON && twoExit == EC_LOST ) || ( oneExit == EC_LOST && twoExit == EC_WON ) )
140 {
141 System.out.println( "OK" );
142 System.exit( 0 );
143 }
144 else
145 {
146 System.out.println( "FAILED: one=" + oneExit + " two=" + twoExit );
147 System.exit( EC_FAILED );
148 }
149 }
150 else if ( "perform".equals( mode ) )
151 {
152 String processName = ManagementFactory.getRuntimeMXBean().getName();
153 System.out.println( processName + " > started" );
154 boolean won = false;
155 long sleepMs = Long.parseLong( args[2] );
156 try ( FileChannel latchChannel = FileChannel.open( latchFile, StandardOpenOption.READ ) )
157 {
158 try ( FileLock latchLock = latchChannel.lock( 0L, 1L, true ) )
159 {
160 System.out.println( processName + " > latchLock acquired" );
161 try ( FileChannel channel = FileChannel.open( path, StandardOpenOption.READ,
162 StandardOpenOption.WRITE, StandardOpenOption.CREATE ) )
163 {
164 try ( FileLock lock = channel.tryLock( 0L, 1L, false ) )
165 {
166 if ( lock != null && lock.isValid() && !lock.isShared() )
167 {
168 System.out.println( processName + " > WON" );
169 won = true;
170 Thread.sleep( sleepMs );
171 }
172 else
173 {
174 System.out.println( processName + " > LOST" );
175 }
176 }
177 }
178 }
179 }
180 System.out.println( processName + " > ended" );
181 if ( won )
182 {
183 System.exit( EC_WON );
184 }
185 else
186 {
187 System.exit( EC_LOST );
188 }
189 }
190 else
191 {
192 System.err.println( "Unknown mode: " + mode );
193 }
194 System.exit( EC_ERROR );
195 }
196 }