I'm trying to fix a piece of code I've written that currently has race conditions. In doing so I need to put the condition of a while loop in a synchronized block, however I don't want to synchronise the whole while block since that would starve other threads of the resource, which they need. I can't figure a reasonable way of doing it without repetition or breaks in places that slightly obscure the control flow. Below is the gist of the problem code:
while ((numRead = in.read(buffer)) != -1) {
out.write(buffer);
}
and I need to synchronise the use of in. The two potential solutions I could think of (but don't think they're very good) are:
synchronized (this) {
numRead = in.read(buffer);
}
while (numRead != -1) {
out.write(buffer);
synchronized (this) {
numRead = in.read(buffer);
}
}
which has undesirable repetition, and this:
while (true) {
synchronized (this) {
numRead = in.read(buffer);
}
if (numRead == -1)
break;
else
out.write(buffer);
}
which isn't great for readability. Any suggestions?
Try it like below.
public testMyMethod () {
byte[] buffer = new int[1024];
int numRead = -1;
while ((numRead = readInput(buffer)) != -1) {
out.write(buffer);
}
}
//first method
int readInput(byte[] buffer) {
int readLen = -1;
synchronized(in) {
in.read(buffer);
}
return readLen;
}
//second method, more performant about 3 times, just the synchronization parts
private static final ReentrantLock inputLock = new ReentrantLock();
int readInput(byte[] buffer) {
int readLen = -1;
inputLock.lock();
try {
readLen = in.read(buffer);
} finally {
inputLock.unlock();
}
return readLen;
}
Related
I have a PublishSubject with this configuration:
PublishSubject<Message> messageObserver =
messageObserver
.filter(t -> test(t))
.buffer(eventsSaveTimeSpanInSeconds, TimeUnit.SECONDS, eventsSaveCount)
.subscribe(messages -> saveToDB(messages));
Different threads of my application are writing messages to this PublishSubject via onNext().
As I see, the buffer underlying ObservableBufferTimed.BufferExactBoundedObserver is non thread-safe, because its onNext looks as follows:
public void onNext(T t) {
U b;
synchronized (this) {
b = buffer;
if (b == null) {
return;
}
b.add(t);
if (b.size() < maxSize) {
return;
}
buffer = null;
producerIndex++;
}
if (restartTimerOnMaxSize) {
timer.dispose();
}
fastPathOrderedEmit(b, false, this);
try {
b = ObjectHelper.requireNonNull(bufferSupplier.call(), "The buffer supplied is null");
} catch (Throwable e) {
Exceptions.throwIfFatal(e);
actual.onError(e);
dispose();
return;
}
synchronized (this) {
buffer = b;
consumerIndex++;
}
if (restartTimerOnMaxSize) {
timer = w.schedulePeriodically(this, timespan, timespan, unit);
}
}
To make the race condition case more obvious I set the eventsSaveTimeSpanInSeconds and eventsSaveCountparams to 1 (1 event in 1 second).
The problem appears in this block:
synchronized (this) {
b = buffer;
if (b == null) {
return;
}
b.add(t);
if (b.size() < maxSize) {
return;
}
buffer = null;
producerIndex++;
}
So, if two messages are buffering at the same time then first message fills the buffer and assigns null to buffer variable. New buffer will be initialized later after the synchronized block. If there is a race condition, when the buffer is null, the second message will not buffered because of the code:
if (b == null) {
return;
}
Is this a defect or a corrrect buffer behavior? How can I avoid this situation?
Use a serialized subject if multiple threads want to call onNext:
Subject<Message> messageObserver = PublishSubject.<Message>create().toSerialized();
messageObserver
.filter(t -> test(t))
.buffer(eventsSaveTimeSpanInSeconds, TimeUnit.SECONDS, eventsSaveCount)
.subscribe(messages -> saveToDB(messages));
// from any thread now
messageObserver.onNext(message);
I am working on a project for my Intro to Java course. I submitted my code and the reviewer said I needed to rewrite the following:
public void move()
{
if (iCanWin() > -1)
{
moveOnColumn(iCanWin());
}
else if (theyCanWin(0, 0, false) > -1)
{
moveOnColumn(theyCanWin(0, 0, false));
else
{
moveOnColumn(brilliantMove());
}
}
int nextMove = iCanWin();
if(nextMove > -1) {
moveOnColumn(nextMove);
} else ...
Not sure what should come after the else... The reviewer said that this would avoid the repetitive calling of the same method.
generally in statement if-ifelse-else
if (check a condition is true?)
{
moveOnColumn(iCanWin()); //do something
}
else if (other condition is true?)
{
moveOnColumn(theyCanWin(0, 0, false)); //do something
else//otherwise
{
moveOnColumn(brilliantMove()); //if previous condition doesn't be true
almost one of them this line go to be execute
}
Just remove the repetitive calls where possible as #ajb mentioned
public void move(){
int nextMove = iCanWin();
if (nextMove <= -1){
nextMove = theyCanWin(0, 0, false);
if(nextMove <= -1){
nextMove = brilliantMove();
}
}
moveOnColumn(nextMove);
}
I am new to distributed parallel programming. In the following code the process 0 gets stuck on MPI.Recv method execution..
if (me != 0) {
if (finalTour != null) {
Node[] nodes = new Node[5];
nodes[0] = finalTour;
MPI.COMM_WORLD.Send(nodes, 0, 5, MPI.OBJECT, 0, 0);
}
}
if (me == 0) {
for (int i = 1; i < processes; i++) {
Node[] nodes = new Node[5];
MPI.COMM_WORLD.Recv(nodes, 0, 5, MPI.OBJECT, MPI.ANY_SOURCE, MPI.ANY_TAG);
if (nodes[0] != null) {
if (finalTour != null) {
if (finalTour.cost > nodes[0].cost) {
finalTour = nodes[0];
}
minCostPath = finalTour;
} else {
finalTour = nodes[0];
minCostPath = finalTour;
}
}
}
}
MPI.Finalize();
if (minCostPath != null) {
print(size, minCostPath);
}
When I debugged this snippet, I observed the following:
1. Sometimes the Recv method is executed before the corresponding send method does. Could this pose a problem?
2. All the processes except 0 send a message to process 0 and execute their MPI.Finalize() method, while process 0 is waiting on a Recv. Could the problem be because of this?
I have trouble with networking in java. I have tried to read a message from a client over sockets. I use BufferedReader for reading the message.
public String read() throws IOException {
String message = reader.readLine();
return message;
}
When I am on reader.readline() method on the server, if the client kills the connection I expect an error actually. However, instead of throwing an exception, it returns NULL.
#Eray Tuncer
it depends on when the connection was closed if it is before start reading the line then yes you should expect an exception. but if it is in between reading I think you will get "null" indicating end of the stream. Please check the following implementation of readLine from BufferedReader :
String readLine(boolean ignoreLF) throws IOException {
StringBuffer s = null;
int startChar;
synchronized (lock) {
ensureOpen(); //This method ensures that the stream is open and this is called before start reading
..................
................
//----Now reading operation started if the connection is closed it will just return a null---------
bufferLoop:
for (;;) {
if (nextChar >= nChars)
fill();
if (nextChar >= nChars) { /* EOF */
if (s != null && s.length() > 0)
return s.toString();
else
return null;
}
boolean eol = false;
char c = 0;
int i;
/* Skip a leftover '\n', if necessary */
if (omitLF && (cb[nextChar] == '\n'))
nextChar++;
skipLF = false;
omitLF = false;
charLoop:
for (i = nextChar; i < nChars; i++) {
c = cb[i];
if ((c == '\n') || (c == '\r')) {
eol = true;
break charLoop;
}
}
startChar = nextChar;
nextChar = i;
if (eol) {
String str;
if (s == null) {
str = new String(cb, startChar, i - startChar);
} else {
s.append(cb, startChar, i - startChar);
str = s.toString();
}
nextChar++;
if (c == '\r') {
skipLF = true;
}
return str;
}
if (s == null)
s = new StringBuffer(defaultExpectedLineLength);
s.append(cb, startChar, i - startChar);
}
}
}
So bottom line is that you should check for null in this operation rather than relying on an IOException. I hope it will help you to fix your problem. Thank you !
You can trigger an exception manually like this:
public String read() throws IOException {
String message = reader.readLine();
if (message == null)
throw new IOException("reader.readLine() returned null");
return message;
}
I have a problem, I need to compare two inputstreams fast.
Today I have a function like this:
private boolean isEqual(InputStream i1, InputStream i2) throws IOException {
try {
// do the compare
while (true) {
int fr = i1.read();
int tr = i2.read();
if (fr != tr)
return false;
if (fr == -1)
return true;
}
} finally {
if (i1 != null)
i1.close();
if (i2 != null)
i2.close();
}
}
But it's really slow. I want to use buffered reads but have not come up with a good way of doing it.
Some extra stuff that makes it harder:
I don't want to read one of the input streams into memory (the whole one)
I don't want to use a third party library
I need a practial solution - code! :)
By far my favorite is to use the org.apache.commons.io.IOUtils helper class from the Apache Commons IO library:
IOUtils.contentEquals( is1, is2 );
Something like this may do:
private static boolean isEqual(InputStream i1, InputStream i2)
throws IOException {
ReadableByteChannel ch1 = Channels.newChannel(i1);
ReadableByteChannel ch2 = Channels.newChannel(i2);
ByteBuffer buf1 = ByteBuffer.allocateDirect(1024);
ByteBuffer buf2 = ByteBuffer.allocateDirect(1024);
try {
while (true) {
int n1 = ch1.read(buf1);
int n2 = ch2.read(buf2);
if (n1 == -1 || n2 == -1) return n1 == n2;
buf1.flip();
buf2.flip();
for (int i = 0; i < Math.min(n1, n2); i++)
if (buf1.get() != buf2.get())
return false;
buf1.compact();
buf2.compact();
}
} finally {
if (i1 != null) i1.close();
if (i2 != null) i2.close();
}
}
Using buffered reads is just a matter of wrapping the InputStreams with BufferedInputStreams. However you are likely to get the best performance reading large blocks at a time.
private boolean isEqual(InputStream i1, InputStream i2) throws IOException {
byte[] buf1 = new byte[64 *1024];
byte[] buf2 = new byte[64 *1024];
try {
DataInputStream d2 = new DataInputStream(i2);
int len;
while ((len = i1.read(buf1)) > 0) {
d2.readFully(buf2,0,len);
for(int i=0;i<len;i++)
if(buf1[i] != buf2[i]) return false;
}
return d2.read() < 0; // is the end of the second file also.
} catch(EOFException ioe) {
return false;
} finally {
i1.close();
i2.close();
}
}
why not simply wrap both streams at the very beginning of your method:
i1 = new BufferedInputStream(i1);
i2 = new BufferedInputStream(i2);
Alternatively, you could simply try reading both streams into a buffer:
public static boolean equals(InputStream i1, InputStream i2, int buf) throws IOException {
try {
// do the compare
while (true) {
byte[] b1 = new byte[buf];
byte[] b2 = new byte[buf];
int length = i1.read(b1);
if (length == -1) {
return i2.read(b2, 0, 1) == -1;
}
try {
StreamUtils.readFully(i2, b2, 0, length);
} catch (EOFException e) {
// i2 is shorter than i1
return false;
}
if (!ArrayUtils.equals(b1, b2, 0, length)) {
return false;
}
}
} finally {
// simply close streams and ignore (log) exceptions
StreamUtils.close(i1, i2);
}
}
// StreamUtils.readFully(..)
public static void readFully(InputStream in, byte[] b, int off, int len) throws EOFException, IOException {
while (len > 0) {
int read = in.read(b, off, len);
if (read == -1) {
throw new EOFException();
}
off += read;
len -= read;
}
}
// ArrayUtils.equals(..)
public static boolean equals(byte[] a, byte[] a2, int off, int len) {
if (off < 0 || len < 0 || len > a.length - off || len > a2.length - off) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return true;
}
if (a == a2) {
return true;
}
if (a == null || a2 == null) {
return false;
}
for (int i = off; i < off + len; i++) {
if (a[i] != a2[i]) {
return false;
}
}
return true;
}
EDIT: I've fixed my implementation now. That's how it looks like without DataInputStream or NIO. Code is available at GitHub or from Sonatype's OSS Snapshot Repository Maven:
<dependency>
<groupId>at.molindo</groupId>
<artifactId>molindo-utils</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>