-
Notifications
You must be signed in to change notification settings - Fork 11.2k
BaseEncoding: Make encodingStream().close() idempotent #8183
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -645,9 +645,13 @@ public OutputStream encodingStream(Writer out) { | |
| int bitBuffer = 0; | ||
| int bitBufferLength = 0; | ||
| int writtenChars = 0; | ||
| boolean closed = false; | ||
|
|
||
| @Override | ||
| public void write(int b) throws IOException { | ||
| public synchronized void write(int b) throws IOException { | ||
| if (closed) { | ||
| throw new IOException("Stream is closed"); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "Steam is closed" is repeated twice. Shouldn't that be defined as a reusable constant?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The Guava pattern for this is a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fair enough. |
||
| } | ||
| bitBuffer <<= 8; | ||
| bitBuffer |= b & 0xFF; | ||
| bitBufferLength += 8; | ||
|
|
@@ -660,12 +664,19 @@ public void write(int b) throws IOException { | |
| } | ||
|
|
||
| @Override | ||
| public void flush() throws IOException { | ||
| public synchronized void flush() throws IOException { | ||
| if (closed) { | ||
| throw new IOException("Stream is closed"); | ||
| } | ||
| out.flush(); | ||
| } | ||
|
|
||
| @Override | ||
| public void close() throws IOException { | ||
| public synchronized void close() throws IOException { | ||
| if (closed) { | ||
| return; | ||
| } | ||
| closed = true; | ||
| if (bitBufferLength > 0) { | ||
| int charIndex = (bitBuffer << (alphabet.bitsPerChar - bitBufferLength)) & alphabet.mask; | ||
| out.write(alphabet.encode(charIndex)); | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Synchronization is required for reliable communication between threads as well as for mutual exclusion.
Synchronization is not guaranteed to work unless both read and write operations are synchronized.
"Occasionally a program that synchronizes only writes (or reads) may appear to work on some machines, but in this case, appearances are deceiving."
--- Item 78 of Effective Java Programming by Joshua Blosch.
What justifies the need for the write of an abstract class to be synchronised without synchronising the read?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All three methods that access the
closedfield —write(),flush(), andclose()— aresynchronized. Both the write toclosed(inclose()) and the reads ofclosed(inwrite()andflush()) happen within synchronized methods. There is no unsynchronized read.This matches
CharSequenceReader, which synchronizes every method. The synchronization was added per @cpovirk's guidance to ensureclose()andwrite()cannot interleave.