Skip to content

Commit 8134888

Browse files
committed
[BAEL-3601] - Fix code review comments.
1 parent b0869b1 commit 8134888

File tree

14 files changed

+164
-528
lines changed

14 files changed

+164
-528
lines changed

core-java-modules/core-java-nio-2/README.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,4 @@ This module contains articles about core Java non-blocking input and output (IO)
88
- [Create a Symbolic Link with Java](https://www.baeldung.com/java-symlink)
99
- [Introduction to the Java NIO Selector](https://www.baeldung.com/java-nio-selector)
1010
- [Using Java MappedByteBuffer](https://www.baeldung.com/java-mapped-byte-buffer)
11-
- [How to Lock a File in Java](https://www.baeldung.com/how-to-lock-a-file-in-java)
12-
- [[<-- Prev]](/core-java-modules/core-java-nio)
11+
- [[<-- Prev]](/core-java-modules/core-java-nio)
Lines changed: 115 additions & 215 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package com.baeldung.lock;
22

33
import java.io.FileInputStream;
4-
import java.io.FileNotFoundException;
54
import java.io.FileOutputStream;
65
import java.io.IOException;
76
import java.io.RandomAccessFile;
@@ -10,230 +9,131 @@
109
import java.nio.channels.FileLock;
1110
import java.nio.channels.NonReadableChannelException;
1211
import java.nio.channels.NonWritableChannelException;
13-
import java.nio.channels.OverlappingFileLockException;
12+
import java.nio.charset.StandardCharsets;
1413
import java.nio.file.Files;
1514
import java.nio.file.Path;
16-
import java.nio.file.Paths;
1715
import java.nio.file.StandardOpenOption;
18-
import java.util.concurrent.CountDownLatch;
19-
import java.util.concurrent.atomic.AtomicInteger;
20-
import java.util.stream.Stream;
2116

2217
import org.slf4j.Logger;
2318
import org.slf4j.LoggerFactory;
2419

2520
import com.google.common.base.Charsets;
2621

27-
2822
public class FileLocks {
29-
30-
private static Logger log = LoggerFactory.getLogger(FileLocks.class);
31-
32-
// Write locks
33-
/**
34-
* Trying to get an exclusive lock on a read-only FileChannel won't work.
35-
*/
36-
static void getExclusiveLockFromInputStream() throws IOException, NonWritableChannelException {
37-
Path path = Files.createTempFile("foo", "txt");
38-
try (FileInputStream fis = new FileInputStream(path.toFile()); FileLock lock = fis.getChannel().lock()) {
39-
log.debug("This won't happen");
40-
} catch (NonWritableChannelException e) {
41-
log.error(
42-
"The channel obtained through a FileInputStream isn't writable. "
43-
+ "You can't obtain an exclusive lock on it!");
44-
throw e;
45-
}
46-
}
47-
48-
49-
/**
50-
* Getting an exclusive lock from a RandomAccessFile works if the file is in write mode.
51-
* @param from beginning of the locked region
52-
* @param size how many bytes to lock
53-
* @return
54-
* @throws IOException
55-
*/
56-
static FileLock getExclusiveLockFromRandomAccessFile(long from, long size) throws IOException {
57-
Path path = Files.createTempFile("foo", "txt");
58-
try (RandomAccessFile file = new RandomAccessFile(path.toFile(), "rw");
59-
FileLock lock = file.getChannel().lock(from, size, false)) {
60-
if (lock.isValid()) {
61-
log.debug("This is a valid exclusive lock");
62-
return lock;
63-
}
64-
return null;
65-
} catch (Exception e) {
66-
System.out.println(e.getMessage());
67-
}
68-
return null;
69-
}
70-
71-
/**
72-
* Getting a write lock on a file region
73-
*/
74-
static FileLock getExclusiveLockFromFileChannelOpen(long from, long size) throws IOException {
75-
Path path = Files.createTempFile("foo", "txt");
76-
try (FileChannel channel = FileChannel.open(path, StandardOpenOption.APPEND);
77-
FileLock lock = channel.lock(from, size, false)) {
78-
String text = "Hello, world.";
79-
ByteBuffer buffer = ByteBuffer.allocate(text.length() + System.lineSeparator().length());
80-
buffer.put((text + System.lineSeparator()).getBytes(Charsets.UTF_8));
81-
buffer.flip();
82-
while (buffer.hasRemaining()) {
83-
channel.write(buffer, channel.size());
84-
}
85-
log.debug("This was written to the file");
86-
Files.lines(path).forEach(System.out::println);
87-
return lock;
88-
}
89-
}
90-
91-
// Read locks
92-
/**
93-
* Trying to get a shared lock on a write-only FileChannel won't work.
94-
*/
95-
static void getReadLockFromOutputStream(long from, long size) throws IOException {
96-
Path path = Files.createTempFile("foo", "txt");
97-
try (FileOutputStream fis = new FileOutputStream(path.toFile());
98-
FileLock lock = fis.getChannel().lock(0, Long.MAX_VALUE, true)) {
99-
log.debug("This won't happen");
100-
} catch (NonReadableChannelException e) {
101-
log.error(
102-
"The channel obtained through a FileOutputStream isn't readable. "
103-
+ "You can't obtain an shared lock on it!");
104-
throw e;
105-
}
106-
}
107-
108-
/**
109-
* Locking a file for reading doesn't require a writable FileChannel.
110-
*
111-
* @param from beginning of the locked region
112-
* @param size how many bytes to lock
113-
* @return
114-
* @throws IOException
115-
*/
116-
static FileLock getReadLockFromInputStream(long from, long size) throws IOException {
117-
Path path = Files.createTempFile("foo", "txt");
118-
try (FileInputStream fis = new FileInputStream(path.toFile());
119-
FileLock lock = fis.getChannel().lock(from, size, true)) {
120-
if (lock.isValid()) {
121-
log.debug("This is a valid shared lock");
122-
return lock;
123-
}
124-
return null;
125-
}
126-
}
127-
128-
129-
/**
130-
* Getting an exclusive lock from a RandomAccessFile works if the file is in read mode.
131-
* @param from beginning of the locked region
132-
* @param size how many bytes to lock
133-
* @return
134-
* @throws IOException
135-
*/
136-
static FileLock getReadLockFromRandomAccessFile(long from, long size) throws IOException {
137-
Path path = Files.createTempFile("foo", "txt");
138-
try (RandomAccessFile file = new RandomAccessFile(path.toFile(), "r"); // could also be "rw", but "r" is sufficient for reading
139-
FileLock lock = file.getChannel().lock(from, size, true)) {
140-
if (lock.isValid()) {
141-
log.debug("This is a valid shared lock");
142-
return lock;
143-
}
144-
return null;
145-
} catch (Exception e) {
146-
log.error(e.getMessage());
147-
}
148-
return null;
149-
}
150-
151-
152-
153-
static class Writer implements Runnable {
154-
155-
private Path path;
156-
157-
private volatile RandomAccessFile file;
158-
159-
private String text;
160-
161-
private volatile CountDownLatch countDownLatch;
162-
163-
/**
164-
*
165-
* @param path The path to the file we will write into
166-
* @param text The text to write
167-
* @param countDownLatch A counter for thread synchronization
168-
*
169-
*/
170-
public Writer(Path path, String text, CountDownLatch countDownLatch) {
171-
this.path = path;
172-
this.text = text;
173-
this.countDownLatch = countDownLatch;
174-
}
175-
176-
@Override
177-
public void run() {
178-
try {
179-
lockAndWrite();
180-
} catch (InterruptedException | FileNotFoundException e) {
181-
// TODO Auto-generated catch block
182-
e.printStackTrace();
183-
}
184-
countDownLatch.countDown();
185-
}
186-
187-
private void lockAndWrite() throws InterruptedException, FileNotFoundException {
188-
ByteBuffer buffer = null;
189-
if (file == null) {
190-
file = new RandomAccessFile(path.toFile(), "rw");
191-
}
192-
try (FileChannel channel = file.getChannel()) {
193-
194-
try (FileLock lock = channel.tryLock(channel.size(),
195-
channel.size() + text.length() + System.lineSeparator().length(), true)) {
196-
if (lock != null) {
197-
String text = "Hello, world.";
198-
buffer = ByteBuffer.allocate(text.length() + System.lineSeparator().length());
199-
buffer.put((text + System.lineSeparator()).getBytes(Charsets.UTF_8));
200-
buffer.flip();
201-
while (buffer.hasRemaining()) {
202-
channel.write(buffer, channel.size());
203-
}
204-
}
205-
} catch (OverlappingFileLockException e) {
206-
// Failed to lock. Try again later.
207-
Thread.sleep(50);
208-
lockAndWrite();
209-
}
210-
} catch (IOException e) {
211-
// TODO Auto-generated catch block
212-
e.printStackTrace();
213-
}
214-
215-
}
216-
217-
}
218-
219-
public static void main(String[] args) throws InterruptedException, IOException {
220-
Path path = Paths.get("/tmp/foo");
221-
Files.deleteIfExists(path);
222-
Files.createFile(path);
223-
int concurrentWriters = 5;
224-
CountDownLatch countDownLatch = new CountDownLatch(concurrentWriters);
225-
// Launch 10 writers in parallel
226-
final AtomicInteger count = new AtomicInteger(0);
227-
Stream.generate(() -> new Thread(new Writer(path, "foo " + count.incrementAndGet(), countDownLatch)))
228-
.limit(concurrentWriters).forEach(Thread::start);
22923

230-
countDownLatch.await();
231-
AtomicInteger lineCount = new AtomicInteger(0);
232-
Files.lines(path).forEach((line) -> {
233-
lineCount.incrementAndGet();
234-
System.out.println(line);
235-
});
236-
log.info("Total lines written = " + lineCount.get());
24+
private static final Logger LOG = LoggerFactory.getLogger(FileLocks.class);
25+
26+
// Write locks
27+
28+
/**
29+
* Trying to get an exclusive lock on a read-only FileChannel won't work.
30+
*/
31+
static void getExclusiveLockFromInputStream() throws IOException {
32+
Path path = Files.createTempFile("foo", "txt");
33+
try (FileInputStream fis = new FileInputStream(path.toFile()); FileLock lock = fis.getChannel().lock()) {
34+
LOG.debug("This won't happen");
35+
} catch (NonWritableChannelException e) {
36+
LOG.error("The channel obtained through a FileInputStream isn't writable. You can't obtain an exclusive lock on it!");
37+
throw e;
38+
}
39+
}
40+
41+
/**
42+
* Gets an exclusive lock from a RandomAccessFile. Works because the file is writable.
43+
* @param from beginning of the locked region
44+
* @param size how many bytes to lock
45+
* @return A lock object representing the newly-acquired lock
46+
* @throws IOException if there is a problem creating the temporary file
47+
*/
48+
static FileLock getExclusiveLockFromRandomAccessFile(long from, long size) throws IOException {
49+
Path path = Files.createTempFile("foo", "txt");
50+
try (RandomAccessFile file = new RandomAccessFile(path.toFile(), "rw"); FileLock lock = file.getChannel().lock(from, size, false)) {
51+
if (lock.isValid()) {
52+
LOG.debug("This is a valid exclusive lock");
53+
return lock;
54+
}
55+
return null;
56+
} catch (Exception e) {
57+
LOG.error(e.getMessage());
58+
}
59+
return null;
60+
}
61+
62+
/**
63+
* Acquires an exclusive lock on a file region.
64+
* @param from beginning of the locked region
65+
* @param size how many bytes to lock
66+
* @return A lock object representing the newly-acquired lock
67+
* @throws IOException if there is a problem creating the temporary file
68+
*/
69+
static FileLock getExclusiveLockFromFileChannelOpen(long from, long size) throws IOException {
70+
Path path = Files.createTempFile("foo", "txt");
71+
try (FileChannel channel = FileChannel.open(path, StandardOpenOption.APPEND); FileLock lock = channel.lock(from, size, false)) {
72+
String text = "Hello, world.";
73+
ByteBuffer buffer = ByteBuffer.allocate(text.length() + System.lineSeparator().length());
74+
buffer.put((text + System.lineSeparator()).getBytes(StandardCharsets.UTF_8));
75+
buffer.flip();
76+
while (buffer.hasRemaining()) {
77+
channel.write(buffer, channel.size());
78+
}
79+
LOG.debug("This was written to the file");
80+
Files.lines(path).forEach(LOG::debug);
81+
return lock;
82+
}
83+
}
84+
85+
// Read locks
86+
87+
/**
88+
* Trying to get a shared lock on a write-only FileChannel won't work.
89+
*/
90+
static void getReadLockFromOutputStream() throws IOException {
91+
Path path = Files.createTempFile("foo", "txt");
92+
try (FileOutputStream fis = new FileOutputStream(path.toFile()); FileLock lock = fis.getChannel().lock(0, Long.MAX_VALUE, true)) {
93+
LOG.debug("This won't happen");
94+
} catch (NonReadableChannelException e) {
95+
LOG.error("The channel obtained through a FileOutputStream isn't readable. " + "You can't obtain an shared lock on it!");
96+
throw e;
97+
}
98+
}
99+
100+
/**
101+
* Gets a lock from an <tt>InputStream</tt>.
102+
* @param from beginning of the locked region
103+
* @param size how many bytes to lock
104+
* @return A lock object representing the newly-acquired lock
105+
* @throws IOException if there is a problem creating the temporary file
106+
*/
107+
static FileLock getReadLockFromInputStream(long from, long size) throws IOException {
108+
Path path = Files.createTempFile("foo", "txt");
109+
try (FileInputStream fis = new FileInputStream(path.toFile()); FileLock lock = fis.getChannel().lock(from, size, true)) {
110+
if (lock.isValid()) {
111+
LOG.debug("This is a valid shared lock");
112+
return lock;
113+
}
114+
return null;
115+
}
116+
}
117+
118+
/**
119+
* Gets an exclusive lock from a RandomAccessFile. Works because the file is readable.
120+
* @param from beginning of the locked region
121+
* @param size how many bytes to lock
122+
* @return A lock object representing the newly-acquired lock
123+
* @throws IOException if there is a problem creating the temporary file
124+
*/
125+
static FileLock getReadLockFromRandomAccessFile(long from, long size) throws IOException {
126+
Path path = Files.createTempFile("foo", "txt");
127+
try (RandomAccessFile file = new RandomAccessFile(path.toFile(), "r"); // could also be "rw", but "r" is sufficient for reading
128+
FileLock lock = file.getChannel().lock(from, size, true)) {
129+
if (lock.isValid()) {
130+
LOG.debug("This is a valid shared lock");
131+
return lock;
132+
}
133+
} catch (Exception e) {
134+
LOG.error(e.getMessage());
135+
}
136+
return null;
137+
}
237138

238-
}
239139
}

0 commit comments

Comments
 (0)