There is a task: to make a multi-threaded execution of functions using AsynchronousSocketChannel. To simulate long work on the server side i'm using Thread.sleep() (stored in the class Worker). If I sleep() threads for more than 2 seconds, when obtaining data on the client side using ByteBuffer and Future, flies java.lang.IndexOutOfBoundsException (my function printFuncResult) Tell me, please, what's the problem?
Server:
public class Server {
public static final InetSocketAddress hostAddress = new InetSocketAddress("localhost", 5678);
private AsynchronousServerSocketChannel serverChannel;
private AsynchronousSocketChannel clientChannel;
ExecutorService threadPool;
public Server() throws IOException, ExecutionException, InterruptedException {
serverChannel = AsynchronousServerSocketChannel.open();
serverChannel.bind(hostAddress);
System.out.println("Server channel bound to port: " + hostAddress.getPort());
System.out.println("Waiting for client to connect... ");
getClientChannel();
handleArguments();
}
private void getClientChannel() throws ExecutionException, InterruptedException {
Future<AsynchronousSocketChannel> acceptResult = serverChannel.accept();
clientChannel = acceptResult.get();
}
private void handleArguments() throws IOException, InterruptedException {
if ((clientChannel != null) && (clientChannel.isOpen())) {
ByteBuffer buffer = ByteBuffer.allocate(32);
Future<Integer> result = clientChannel.read(buffer);
while (! result.isDone()) {
// System.out.println("Result coming... ");
}
buffer.flip();
int x = buffer.getInt(0);
Worker workerOne = new Worker(Worker.TYPE_F, x, clientChannel);
Worker workerTwo = new Worker(Worker.TYPE_G, x, clientChannel);
threadPool = Executors.newFixedThreadPool(2);
threadPool.execute(workerOne);
threadPool.execute(workerTwo);
Thread.sleep(3000);
clientChannel.close();
}
}
}
class Worker implements Runnable {
public static final int TYPE_F = 1;
public static final int TYPE_G = 2;
private int x;
private int type;
private AsynchronousSocketChannel clientChannel;
public Worker(int type, int x, AsynchronousSocketChannel clientChannel) {
this.x = x;
this.type = type;
this.clientChannel = clientChannel;
}
private void sendResultToClient(int res) {
ByteBuffer buffer = ByteBuffer.allocate(32);
if (type == TYPE_F) {
res = 4545;
} else {
res = 34234;
}
buffer.putInt(0, type);
buffer.putInt(4, res);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int i = 0; i < 10000; ++i) {
for (int j = 0; j < 10000; ++j) {
int k = i*j + i/(j +1) + i + j + Math.max(i, j);
}
}
boolean written = false;
while (!written) {
try {
clientChannel.write(buffer);
written = true;
} catch (Exception e) {}
}
}
#Override
public void run() {
int result = -1;
Random random = new Random();
switch (type) {
case TYPE_F :
result = (int)Math.pow(x, x);
break;
case TYPE_G :
result = (int)Math.pow(x, x / 2);
break;
}
sendResultToClient(result);
}
}
Client:
public class Client {
private AsynchronousSocketChannel clientChannel;
ExecutorService threadPool;
public Client(int x) throws IOException, InterruptedException, ExecutionException {
threadPool = Executors.newFixedThreadPool(2);
boolean connected = false;
while (!connected) {
try {
clientChannel = AsynchronousSocketChannel.open();
Future<Void> future = clientChannel.connect(Server.hostAddress);
future.get();
connected = true;
} catch (ExecutionException e) {}
}
System.out.println("Client is started: " + clientChannel.isOpen());
System.out.println("Sending messages to server: ");
sendArguments(x);
//showCancelDialog();
listenResult();
clientChannel.close();
}
private void sendArguments(int x) throws InterruptedException, IOException {
ByteBuffer buffer = ByteBuffer.allocate(32);
buffer.putInt(0, x);
Future<Integer> result = clientChannel.write(buffer);
while (! result.isDone()) {
System.out.println("... ");
}
}
private boolean waitForResult(Future <Pair <Integer, Integer>> futureResult) {
Scanner sc = new Scanner(System.in);
while (!futureResult.isDone() ) {
System.out.println("DOING.. break? (y/n)");
String input = sc.next();
if (input.equals("y")) {
System.out.println("CANCELLED");
threadPool.shutdownNow();
return false;
}
}
return true;
}
private void printFuncResult(Future <Pair <Integer, Integer>> futureResult) throws ExecutionException, InterruptedException {
Integer funcType = new Integer(futureResult.get().getKey());
Integer result = new Integer(futureResult.get().getValue());
System.out.println("RESULT OF "+ funcType +" FUNC = " + result);
}
private void listenResult() throws ExecutionException, InterruptedException {
System.out.println("Wating for result...");
Listener listener = new Listener(clientChannel);
Future <Pair <Integer, Integer>> futureResult = threadPool.submit(listener);
if (!waitForResult(futureResult)) {
return;
}
printFuncResult(futureResult);
futureResult = threadPool.submit(listener);
if (!waitForResult(futureResult)) {
return;
}
printFuncResult(futureResult);
}
}
class Listener implements Callable <Pair <Integer, Integer>> {
private AsynchronousSocketChannel clientChannel;
public Listener(AsynchronousSocketChannel channel) {
this.clientChannel = channel;
}
#Override
public Pair <Integer, Integer> call() throws Exception {
ByteBuffer buffer = ByteBuffer.allocate(32);
Future<Integer> futureResult = clientChannel.read(buffer);
while (! futureResult.isDone()) {}
buffer.flip();
Integer type = new Integer(buffer.getInt(0));
Integer result = new Integer (buffer.getInt(4));
return new Pair<Integer, Integer>(type, result);
}
}
}
The IndexOutOfBoundsException is not coming from printFuncResult. It is only stored in the future and printed with the stack trace there. The IndexOutOfBoundsException is generated in Listener call function on this line:
Integer type = new Integer(buffer.getInt(0));
This will happen if the read did not read a sufficient number of bytes.
I suggest you replace this inefficient and hard to debug while loop .
while (! futureResult.isDone()) {}
with something like
int bytes_read = futureResult.get();
if(bytes_read != 32) {
// log error or throw exception or retry ...
}
Related
java 8
my snippet:
private ThreadedApplicationEventPublisher threadedApplicationEventPublisher;
private final ExecutorService executorService = Executors.newSingleThreadExecutor();
private final List<Long> failedAttemptsList = new
LinkedList<>();
private final Semaphore alarmRaised = new Semaphore(1);
Future<Boolean> future = executorService.submit(new ClearAlarmAndResetAttemptsCallable());
if (future.get().booleanValue()) {
// some code here
}
//...
public class ClearAlarmAndResetAttemptsCallable implements Callable<Boolean> {
#Override
public Boolean call() throws Exception {
LOGGER.info("ClearAlarmAndResetAttemptsCallable: start");
while (true) {
long currentTimeSec = System.currentTimeMillis() / 1000;
LOGGER.info(
"ClearAlarmAndResetAttemptsCallable: in_while, currentTimeSec = {}, failedAttemptsList_size = {}",
currentTimeSec, failedAttemptsList.size());
synchronized (failedAttemptsList) {
LOGGER.info("ClearAlarmAndResetAttemptsCallable: inside_synchronized");
Long lastTimeSec = ((LinkedList<Long>) failedAttemptsList).getLast();
long durationSec = currentTimeSec - lastTimeSec;
if (durationSec > timeWindowSec) {
threadedApplicationEventPublisher.publishEvent(new PossibleMCAttackEventPostEvent(this,
folderService.findNetwork(), EventSeverity.NORMAL, DateUtils.getGmtTime(),
AttackTypeEnum.REPETITIVE_FAILED_LOGON_ATTEMPTS, ""));
failedAttemptsList.clear();
break;
}
}
try {
Thread.sleep(timeWindowSec * 100L);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
}
alarmRaised.release();
return true;
}
}
here result log
ClearAlarmAndResetAttemptsCallable: start
ClearAlarmAndResetAttemptsCallable: in_while, currentTimeSec = 1648120833, failedAttemptsList_size = 3
The question is: Why not print log
ClearAlarmAndResetAttemptsCallable: inside_synchronized
?
I'm trying to simulate a can fruit factory. As the cans are sterilised 4 at a time, the filling takes place. Only the cans that are sterilised can be filled. How do I implement this? Because as for my output, it says that it sterilizes can 1,2,3,4, which means that the next stage, it it supposed to fill can 1, but instead, it fills can 5
public static void main(String[] args) throws
ExecutionException {
LinkedBlockingQueue<can> belt = new
LinkedBlockingQueue();
LinkedBlockingQueue<can> steril = new
LinkedBlockingQueue(4);
LinkedBlockingQueue<can> fill = new
LinkedBlockingQueue();
ExecutorService factory =
Executors.newCachedThreadPool();
for (int i = 1; i <= 100; i++) {
can c = new can(i);
System.out.println("---------------------------------------");
System.out.println("Can" + c.canNo + " entered factory");
//filling f = new filling(c, steril, fill);
try {
Future<can> dentscan = factory.submit(new dentscanner(c, belt, steril, fill));
Thread.sleep(500);
//factory.submit(f);
} catch (InterruptedException e) {
}
}
}
}
class can {
int canNo;
boolean sterilized = false;
public can(int canNo) {
this.canNo = canNo;
}
}
public dentscanner(can c, LinkedBlockingQueue<can> belt, LinkedBlockingQueue<can> steril, LinkedBlockingQueue fill) {
this.c = c;
this.belt = belt;
this.steril = steril;
this.fill = fill;
}
#Override
public can call() throws Exception {
ExecutorService factory =
Executors.newCachedThreadPool();
sterilisation s = new sterilisation(c, belt, steril, fill);
int dent = rand.nextInt(10);
System.out.println("\tScanning for Can" + c.canNo
+ " for Dents");
if (dent == 3) {
System.out.println("\t\tStatus: Dented");
System.out.println("\t\t\tCan" + c.canNo + "
Rejected");
System.out.println("\t\t\tRemoved from belt");
return null;
} else {
System.out.println("\t\tStatus:No Dents");
System.out.println("\tPassing Can " + c.canNo +
" for sterilisation");
belt.put(c);
factory.submit(s);
Thread.sleep(1000);
return c;
}
}
}
class sterilisation implements Runnable {
can c;
LinkedBlockingQueue<can> belt;
LinkedBlockingQueue<can> steril;
LinkedBlockingQueue<can> fill;
int counter = 0;
public sterilisation(can c, LinkedBlockingQueue<can> belt, LinkedBlockingQueue<can> steril, LinkedBlockingQueue fill) {
this.c = c;
this.belt = belt;
this.steril = steril;
this.fill = fill;
}
#Override
public void run() {
ExecutorService factory = Executors.newCachedThreadPool();
filling f = new filling(c, steril, fill);
try {
can c = belt.take();
steril.put(c);
if (steril.size() == 4) {
for (int i = 1; i < 5; i++) {
try {
System.out.println("Can" + steril.take().canNo + " sterilised");
} catch (InterruptedException ex) {
}
}
c.sterilized = true;
}
if (c.sterilized) {
factory.submit(f);
counter = 0;
}
} catch (InterruptedException ex) {
}
}
}
class filling implements Runnable {
can c;
LinkedBlockingQueue<can> steril;
LinkedBlockingQueue<can> fill;
public filling(can c, LinkedBlockingQueue<can> steril, LinkedBlockingQueue<can> fill) {
this.c = c;
this.steril = steril;
this.fill = fill;
}
#Override
public void run() {
ExecutorService factory = Executors.newCachedThreadPool();
try {
fill.put(steril.take());
System.out.println("Filling Can" + fill.take().canNo);
} catch (InterruptedException ex) {
}
}
}
Here is the output
Passing Can 4 for sterilisation
Can1 sterilised
Can2 sterilised
Can3 sterilised
Can4 sterilised
---------------------------------------
Can5 entered factory
Scanning for Can5 for Dents
Status:No Dents
Passing Can 5 for sterilisation
Filling Can5
Not a complete answer, but a few hints. Model the processes as threads. Sterilization is one thread, processing 4 cans at a time. Filling is another thread, processing one can at a time. Connect the processes (threads) with input and output queues (BlockingQueues):
---Q1--> Sterilization ---Q2--> Filling ---Q3--> ?
After thinking and some experimentation you will find that every "process" has (at least) four properties in common. I'll give you the first two: Input queue and Output queue. The remaining two I leave as an exercise.
The developments of this issue are now described unequivocally in this new question: Why does the JVM show more latency for the same block of code after a busy spin pause?
I'm including below the source codes of a simple server and client that demonstrate and isolate the problem. Basically I'm timing the latency of a ping-pong (client-server-client) message. I start by sending one message every 1 millisecond. I wait for 200k messages to be sent so the HotSpot has a chance to optimize the code. Then I change my pause time from 1 millisecond to 30 seconds. For my surprise my write and read operation become considerably slower.
I don't think it is a JIT/HotSpot problem. I was able to pinpoint the slower method to the native JNI calls to write (write0) and read. It looks like the longer you pause the slower it becomes.
I'm looking for pointers on how to debug, understand, explain or fix this problem.
Server.java:
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
public class Server {
private final ServerSocketChannel serverSocketChannel;
private final ByteBuffer readBuffer = ByteBuffer.allocateDirect(1024);
private final int port;
private final int msgSize;
public Server(int port, int msgSize) throws IOException {
this.serverSocketChannel = ServerSocketChannel.open();
this.port = port;
this.msgSize = msgSize;
}
public void start() throws IOException {
serverSocketChannel.socket().bind(new InetSocketAddress(port));
final SocketChannel socketChannel = serverSocketChannel.accept(); // blocking mode...
System.out.println("Client accepted!");
socketChannel.configureBlocking(false);
socketChannel.socket().setTcpNoDelay(true);
Thread t = new Thread(new Runnable() {
#Override
public void run() {
try {
while(true) {
int bytesRead = socketChannel.read(readBuffer);
if (bytesRead == -1) {
System.out.println("Client disconnected!");
return;
} else if (bytesRead > 0) {
if (readBuffer.position() == msgSize) {
// have a full message there...
readBuffer.flip();
int bytesSent = socketChannel.write(readBuffer);
if (bytesSent != msgSize) throw new RuntimeException("Could not send full message out: " + bytesSent);
readBuffer.clear();
}
}
}
} catch(Exception e) {
throw new RuntimeException(e);
}
}
});
t.start();
serverSocketChannel.close();
}
public static void main(String[] args) throws Exception {
Server s = new Server(9999, 8);
s.start();
}
}
Client.java:
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
public class Client implements Runnable {
private static final int WARMUP = 200000;
private final SocketChannel socketChannel;
private final String host;
private final int port;
private final ByteBuffer outBuffer;
private final ByteBuffer inBuffer = ByteBuffer.allocateDirect(1024);
private final int msgSize;
private final StringBuilder sb = new StringBuilder(1024);
private int interval;
private int totalMessagesSent;
private long timeSent;
private int mod;
public Client(String host, int port, int msgSize) throws IOException {
this.socketChannel = SocketChannel.open();
this.host = host;
this.port = port;
this.outBuffer = ByteBuffer.allocateDirect(msgSize);
this.msgSize = msgSize;
for(int i = 0; i < msgSize; i++) outBuffer.put((byte) i);
outBuffer.flip();
this.interval = 1;
this.mod = 20000;
}
public static long busySleep(long t) {
long x = 0;
for(int i = 0; i < t * 20000; i++) {
x += System.currentTimeMillis() / System.nanoTime();
}
return x;
}
public void start() throws Exception {
this.socketChannel.configureBlocking(false);
this.socketChannel.socket().setTcpNoDelay(true);
this.socketChannel.connect(new InetSocketAddress(host, port));
while(!socketChannel.finishConnect()) {
System.out.println("Waiting to connect");
Thread.sleep(1000);
}
System.out.println("Please wait as output will appear every minute or so. After " + WARMUP + " messages you will see the problem.");
Thread t = new Thread(this);
t.start();
}
private final void printResults(long latency, long timeToWrite, long timeToRead, long zeroReads, long partialReads, long realRead) {
sb.setLength(0);
sb.append(new java.util.Date().toString());
sb.append(" Results: totalMessagesSent=").append(totalMessagesSent);
sb.append(" currInterval=").append(interval);
sb.append(" latency=").append(latency);
sb.append(" timeToWrite=").append(timeToWrite);
sb.append(" timeToRead=").append(timeToRead);
sb.append(" realRead=").append(realRead);
sb.append(" zeroReads=").append(zeroReads);
sb.append(" partialReads=").append(partialReads);
System.out.println(sb);
}
#Override
public void run() {
try {
while(true) {
busySleep(interval);
outBuffer.position(0);
timeSent = System.nanoTime();
int bytesSent = socketChannel.write(outBuffer);
long timeToWrite = System.nanoTime() - timeSent;
if (bytesSent != msgSize) throw new IOException("Can't write message: " + bytesSent);
inBuffer.clear();
long zeroReads = 0;
long partialReads = 0;
long timeToRead = System.nanoTime();
long realRead = 0;
while(inBuffer.position() != msgSize) {
realRead = System.nanoTime();
int bytesRead = socketChannel.read(inBuffer);
if (bytesRead == 0) {
zeroReads++;
} else if (bytesRead == -1) {
System.out.println("Other side disconnected!");
return;
} else if (bytesRead != msgSize) {
partialReads++;
realRead = -1;
} else {
realRead = System.nanoTime() - realRead;
}
}
long now = System.nanoTime();
timeToRead = now - timeToRead;
long latency = now - timeSent;
if (++totalMessagesSent % mod == 0 || totalMessagesSent == 1) {
printResults(latency, timeToWrite, timeToRead, zeroReads, partialReads, realRead);
}
if (totalMessagesSent == WARMUP) {
this.interval = 30000;
this.mod = 1;
}
}
} catch(Exception e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) throws Exception {
Client client = new Client("localhost", 9999, 8);
client.start();
}
}
I execute java -server -cp . Server and java -server -cp . Client. The output of the client is:
Per #dunni request, changing to 1 second delay instead of 30 second delay. Same problem:
One problem you have is that the JVM, the CPU and it's cache are falling asleep when there is no data to read. Once this happens, the machine has to do much more before it can pick up data than it did when your problem was running hot.
the CPU speed may have dropped to save power. e.g. half normal. It can do this on dumb busy loops.
the thread isn't running and has to be restarted on a new CPU. (In you case this should be rare)
the CPU's cache may have been powered down and has to be loaded progressively from L3 cache or main memory
even after your thread returns, it will run slower than normal for up to 100 micro-seconds as the caches pull in more data/code.
you will get a non-maskable interrupt 100+ times per second you can't turn off.
In short if you need consistent latencies you need to
turn off power management.
don't give up the CPU i.e. busy wait. (Which you are doing)
run on isolated CPUs binding the thread with affinity.
disable all maskable interrupts on that core.
use a user space driver for networking instead of the kernel.
NOTE: Given every operation appears to be taking about 2x as long, I would look at power management first.
I was looking at the code of SocketChannelImpl
and noticed that there are two monitors involved in read() - a read lock and a state lock.
My opinion is that locks behave much better when they are hot and uncontested.
Following class is based on your client and only does some locking, similar to what is done in SocketChannelImpl. From non-observable, the latency becomes ~5000 on my box (win8, jdk8)
import java.util.concurrent.TimeUnit;
public class Locker implements Runnable {
private static final int WARMUP = 40000;
private final Object readLock = new Object();
private final Object writeLock = new Object();
private final Object stateLock = new Object();
private final StringBuilder sb = new StringBuilder(1024);
private long interval;
private int totalMessagesSent;
private long timeSent;
private int mod;
private long totalOps;
private long readerThread;
private long writerThread;
public Locker() {
this.interval = 1;
this.mod = 20000;
}
public static long busySleep(long t) throws InterruptedException {
long until = System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(t);
while(System.nanoTime() < until);
return until;
}
public void start() throws Exception {
Thread t = new Thread(this);
t.start();
}
private final void printResults(long latency, long timeToRead) {
sb.setLength(0);
sb.append(new java.util.Date().toString());
sb.append(" Results: totalMessagesSent=").append(totalMessagesSent);
sb.append(" currInterval=").append(interval);
sb.append(" latency=").append(latency);
sb.append(" timeToRead=").append(timeToRead);
sb.append(" totalOps=").append(totalOps);
sb.append(" reader=").append(readerThread);
sb.append(" writer=").append(writerThread);
System.out.println(sb);
}
#Override
public void run() {
try {
while(true) {
busySleep(interval);
timeSent = System.nanoTime();
try {
synchronized (writeLock) {
synchronized (stateLock) {
writerThread = Thread.currentThread().getId();
}
totalOps++;
}
}
finally {
synchronized (stateLock) {
writerThread = 0;
}
}
long timeToRead = System.nanoTime();
try {
synchronized (readLock) {
synchronized (stateLock) {
readerThread = Thread.currentThread().getId();
}
totalOps++;
}
} finally {
synchronized (stateLock) {
readerThread = 0;
}
}
long now = System.nanoTime();
timeToRead = now - timeToRead;
long latency = now - timeSent;
if (++totalMessagesSent % mod == 0 || totalMessagesSent == 1) {
printResults(latency, timeToRead);
}
if (totalMessagesSent == WARMUP) {
this.interval = 5000;
this.mod = 1;
}
}
} catch(Exception e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) throws Exception {
Locker locker = new Locker();
locker.start();
}
}
EDIT: modified code per OP's suggestion exhibiting the same latency increase:
import java.util.Arrays;
import java.util.concurrent.TimeUnit;
public class Locker {
static final int WARMUP = 20000;
final Object readLock = new Object();
final Object writeLock = new Object();
final Object stateLock = new Object();
long interval = 1;
int totalMessagesSent;
long totalOps;
long readerThread;
long writerThread;
final long[] measures = new long[WARMUP + 20];
static long busySleep(long t) {
long until = System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(t);
while(System.nanoTime() < until);
return until;
}
void printResults(long latency, long timeToRead) {
if (readerThread != 0 || writerThread != 0 || totalMessagesSent > totalOps || timeToRead < 0) throw new Error();
measures[totalMessagesSent] = latency;
}
void run() {
while(totalMessagesSent < measures.length) {
busySleep(interval);
long timeSent = System.nanoTime();
try {
synchronized (writeLock) {
synchronized (stateLock) {
writerThread = Thread.currentThread().getId();
}
totalOps++;
}
}
finally {
synchronized (stateLock) {
writerThread = 0;
}
}
long timeToRead = System.nanoTime();
try {
synchronized (readLock) {
synchronized (stateLock) {
readerThread = Thread.currentThread().getId();
}
totalOps++;
}
} finally {
synchronized (stateLock) {
readerThread = 0;
}
}
long now = System.nanoTime();
timeToRead = now - timeToRead;
long latency = now - timeSent;
printResults(latency, timeToRead);
++totalMessagesSent;
this.interval = (totalMessagesSent/WARMUP * 5000) + 1;
}
System.out.println("last measures = " + Arrays.toString(Arrays.copyOfRange(measures, WARMUP - 20, measures.length - 1)));
}
public static void main(String[] args) {
new Locker().run();
}
}
I am trying to spawn off a handful of threads and place them in a List as they execute. As they complete their processing I would like to collect their results for presentation. That way I can have a list containing many threads and then once they become available I can call future.get and use their callback information.
For some reason, I am missing many of the results. When I step through the code, f.get() is being passed over when it shouldn't be and I cannot figure out why.
My code is as follows:
public class ThreadTesterRunner {
static List<Integer> randoms = new ArrayList<>();
public static void main(String[] args) throws InterruptedException {
final Phaser cb = new Phaser();
ThreadRunner tr = new ThreadRunner(cb);
Thread t = new Thread(tr, "Thread Runner");
t.start();
boolean process = true;
// wait until all threads process, then print reports
while (process){
if(tr.isFinished()){
System.out.println("Print metrics");
process = false;
}
Thread.sleep(1000);
}
}
}
class ThreadRunner implements Runnable {
private ExecutorService executorService = Executors.newFixedThreadPool(10);
private final Phaser barrier;
private boolean finished=false;
public ThreadRunner(Phaser phaser) {this.barrier = phaser;}
public void run(){
try {
List<Future<Integer>> list = new ArrayList<>();
boolean stillLoop = true; int i = 0;
final Phaser p = this.barrier;
Callable<Integer> task = new Callable<Integer>() {
public Integer call() throws Exception {
return new Reader().doRun(p);
}
};
List<Integer> randoms = new ArrayList<>();
Integer size;
while (stillLoop){
System.out.println("i "+i);
list.add(executorService.submit(task));
for(Future<Integer> f: list){
if(f.isDone()){
size = f.get();
System.out.println("size "+size);
list.remove(f);
} else {
// keep processing
}
}
if(i == 2){
System.out.println("breaking out of loop");
stillLoop = false;
}
i++;
}
this.barrier.awaitAdvance(0);
this.finished=true;
} catch (Exception e1) {
e1.printStackTrace();
}
}
public boolean isFinished(){
return this.finished;
}
}
class Reader {
private Phaser readBarrier;
private ExecutorService executorService = Executors.newFixedThreadPool(20);
public Reader() {
}
Random randomGenerator = new Random();
public Integer doRun(Phaser phaser) throws Exception {
phaser.register();
this.readBarrier = phaser;
System.out.println("Reading...");
int i;
int r = randomGenerator.nextInt(100);
System.out.println("r "+r);
ThreadTesterRunner.randoms.add(r);
int a = this.readBarrier.arrive();
return r; //i;
}
}
Any idea's as to why this may be happening?
EDIT:
Alright, I think I have it up and running:
class ThreadRunner implements Runnable {
// static int timeOutTime = 2;
private ExecutorService executorService = Executors.newFixedThreadPool(10);
private final Phaser barrier;
private boolean finished = false;
public ThreadRunner(Phaser phaser) {
this.barrier = phaser;
}
public void run() {
try {
List<Future<Integer>> list = new CopyOnWriteArrayList<>();
boolean stillLoop = true;
int i = 0;
final Phaser p = this.barrier;
Callable<Integer> readerTask = new Callable<Integer>() {
public Integer call() throws Exception {
return new Reader().doRun(p);
}
};
List<Integer> randoms = new ArrayList<>();
Integer size;
while (stillLoop) {
if (i <= 2) {
list.add(executorService.submit(readerTask));
}
if (!list.isEmpty()) {
for (Future<Integer> f : list) {
if (f.isDone()) {
size = f.get();
randoms.add(size);
System.out.println("Process read with a size of "+ size);
list.remove(f);
} else {
// System.out.println("skipping");
}
}
} else {
stillLoop = false;
}
i++;
}
System.out.println("at barrier waiting");
this.barrier.awaitAdvance(0);
System.out.println("barrier crossed");
this.finished = true;
} catch (Exception e1) {
e1.printStackTrace();
}
}
public boolean isFinished() {
return this.finished;
}
}
Results:
i 0
i 1
i 2
breaking out of loop
Reading...
Reading...
r 13
r 44
Reading...
r 78
Print metrics
I changed the ArrayList to a Vector since ArrayList is not thread safe which would eventually cause a ConcurrentModificationException.
Is the above output what you would expect?
I’m writing a program that implements the Producer Consumer problem in Java using multithreading concepts. Below are few details how I’m supposed to do it:
1) The main thread should create a buffer with capacity specified as a command line argument. The number of producer and consumer threads are also specified as command line arguments. I’m supposed to assign a unique number to each producer and consumer thread. How do I assign a unique number to producer and consumer threads?
2) The producer thread operates in an infinite loop. It produces a data item (a string) with the following format: <producer number>_<data item number>. For example the 1st data item from thread number 1 will be 1_1 and second data item from thread number 3 will be 3_2. How do create data items in such a format?
3) Then the Producer thread writes an entry into the producer log file (< producer number > “Generated” <data item>). Upon writing the log entry, it attempts to insert into the buffer. If insertion is successful, it creates an entry into the log file (<producer number> <data item> “Insertion successful”). How do I write such a code?
Below is the Java code I wrote.
import java.util.*;
import java.util.logging.*;
public class PC2
{
public static void main(String args[])
{
ArrayList<Integer> queue = new ArrayList<Integer>();
int size = Integer.parseInt(args[2]);
Thread[] prod = new Thread[Integer.parseInt(args[0])];
Thread[] cons = new Thread[Integer.parseInt(args[1])];
for(int i=0; i<prod.length; i++)
{
prod[i] = new Thread(new Producer(queue, size));
prod[i].start();
}
for(int i=0; i<cons.length; i++)
{
cons[i] = new Thread(new Consumer(queue, size));
cons[i].start();
}
}
}
class Producer extends Thread
{
private final ArrayList<Integer> queue;
private final int size;
public Producer(ArrayList<Integer> queue, int size)
{
this.queue = queue;
this.size = size;
}
public void run()
{
while(true){
for(int i=0; i<size; i++)
{
System.out.println("Produced: "+i+" by id " +Thread.currentThread().getId());
try
{
produce(i);
Thread.sleep(3000);
}
catch(Exception e)
{
Logger.getLogger(Producer.class.getName()).log(Level.SEVERE, null, e);
}
}}
}
public void produce(int i) throws InterruptedException
{
while(queue.size() == size)
{
synchronized(queue)
{
System.out.println("Queue is full "+Thread.currentThread().getName() +" is waiting, size: "+queue.size());
queue.wait();
}
}
synchronized(queue)
{
queue.add(i);
queue.notifyAll();
}
}
}
class Consumer extends Thread
{
private final ArrayList<Integer> queue;
private final int size;
public Consumer(ArrayList<Integer> queue, int size)
{
this.queue = queue;
this.size = size;
}
public void run()
{
while(true)
{
try
{ System.out.println("Consumed: "+consume());
Thread.sleep(1000);
}
catch(Exception e)
{
Logger.getLogger(Consumer.class.getName()).log(Level.SEVERE, null, e);
}
}
}
public int consume() throws InterruptedException
{
while(queue.isEmpty())
{
synchronized(queue)
{
System.out.println("Queue is empty "+Thread.currentThread().getName()+" is waiting, size: "+queue.size());
queue.wait();
}
}
synchronized (queue)
{
queue.notifyAll();
System.out.println("Consumed by id "+Thread.currentThread().getId());
return (Integer) queue.remove(0);
}
}
}
How can I carry out the above steps?
I’m supposed to assign a unique number to each producer and consumer
thread. How do I assign a unique number to producer and consumer
threads?
Add an instance (non-static) variable to the Producer/Consumer classes. When you initialize the new Producer/Consumer Objects, pass in the unique number. You can keep track of what number you're on with an int counter in your main class.
2) The producer thread operates in an infinite loop. It produces a
data item (a string) with the following format: < producer number >_<
data item number > . For example the 1st data item from thread number
1 will be 1_1 and second data item from thread number 3 will be 3_2.
How do create data items in such a format?
Use synchronized methods and/or atomic variables. Look into Java Concurrency.
3) Then the Producer thread writes an entry into the producer log file
(< producer number > “Generated” < data item >). Upon writing the log
entry, it attempts to insert into the buffer. If insertion is
successful, it creates an entry into the log file (< producer number >
< data item > “Insertion successful”). How do I write such a code?
My answer is the same as the previous question: read about Java concurrency. Spend an hour reading about synchronization, locks, and atomic variables and I guarantee you will easily write your program.
For producer consumer problem best solution is BlockingQueue. I was testing a few things so designed same kind of program now modified it as per your need.
See if it helps.
import java.util.concurrent.*;
public class ThreadingExample {
public static void main(String args[]){
BlockingQueue<Message> blockingQueue = new ArrayBlockingQueue<Message>(100);
ExecutorService exec = Executors.newCachedThreadPool();
exec.execute(new Producer(blockingQueue));
exec.execute(new Consumer(blockingQueue));
}
}
class Message{
private static int count=0;
int messageId;
Message(){
this.messageId=count++;
System.out.print("message Id"+messageId+" Created ");
}
}
class Producer implements Runnable{
private BlockingQueue<Message> blockingQueue;
Producer(BlockingQueue<Message> blockingQueue){
this.blockingQueue=blockingQueue;
}
#Override
public void run(){
while(!Thread.interrupted()){
System.out.print("Producer Started");
try {
blockingQueue.put(new Message());
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Producer Done");
}
}
}
class Consumer implements Runnable{
private BlockingQueue<Message> blockingQueue;
Consumer(BlockingQueue<Message> blockingQueue){
this.blockingQueue=blockingQueue;
}
#Override
public void run(){
while(!Thread.interrupted()){
System.out.print("Concumer Started");
try{
Message message = blockingQueue.take();
System.out.print("message Id"+message.messageId+" Consumed ");
}
catch(InterruptedException e){
e.printStackTrace();
}
System.out.println("Concumer Done");
}
}
}
I tried the following which might work for you, except for the buffer condition on 3, which you can add the part of the code by yourself.
Hope this helps.
public class Message {
private String msg;
public Message(String msg) {
super();
this.msg = msg;
}
public String getMsg(){
return msg;
}
}
import java.util.concurrent.BlockingQueue;
public class Producer implements Runnable {
private BlockingQueue<Message> queue;
private boolean run = true;
public Producer(BlockingQueue<Message> queue) {
super();
this.queue = queue;
}
public void setRun(boolean val) {
this.run = val;
}
#Override
public void run() {
int i = 0;
while (run) {
Message msg = new Message(Thread.currentThread().getName() + "_"+ i);
try {
Thread.sleep(i * 100);
queue.put(msg);
System.out.println("Producer: "+Thread.currentThread().getName()+" produced and added to the queue: "+msg.getMsg());
} catch (InterruptedException e) {
e.printStackTrace();
}
i++;
if(i==10){
setRun(false);
System.out.println(Thread.currentThread().getName()+" stopped");
}
}
}
}
import java.util.concurrent.BlockingQueue;
public class Consumer implements Runnable{
private BlockingQueue<Message> queue;
private boolean run = true;
public Consumer(BlockingQueue<Message> queue) {
super();
this.queue = queue;
}
public void setRun(boolean val){
this.run = val;
}
#Override
public void run() {
while(run){
try {
Thread.sleep(100);
Message msg = queue.take();
System.out.println("Consumer: "+Thread.currentThread().getName()+" generated/consumed "+msg.getMsg());
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
import java.util.Scanner;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
public class ProducerConsumerMain {
public static void main(String[] args) {
System.out
.println("please enter the number of producer:consumer:size of the queue in order");
Scanner scan = new Scanner(System.in);
Thread[] prodThreads = new Thread[scan.nextInt()];
Thread[] consThreads = new Thread[scan.nextInt()];
BlockingQueue<Message> queue = new ArrayBlockingQueue<Message>(scan.nextInt());
for (int i = 0; i < prodThreads.length; i++) {
prodThreads[i] = new Thread(new Producer(queue), "" + i);
prodThreads[i].start();
}
for (int i = 0; i < consThreads.length; i++) {
consThreads[i] = new Thread(new Consumer(queue), "" + i);
consThreads[i].start();
}
}
}
Please refer the below code. You can change the constant values based on the command line arguments. I have tested the code, its working as per your requirement.
import java.util.LinkedList;
import java.util.Queue;
public class ProducerConsumerProblem {
public static int CAPACITY = 10; // At a time maximum of 10 tasks can be
// produced.
public static int PRODUCERS = 2;
public static int CONSUMERS = 4;
public static void main(String args[]) {
Queue<String> mTasks = new LinkedList<String>();
for (int i = 1; i <= PRODUCERS; i++) {
Thread producer = new Thread(new Producer(mTasks));
producer.setName("Producer " + i);
producer.start();
}
for (int i = 1; i <= CONSUMERS; i++) {
Thread consumer = new Thread(new Consumer(mTasks));
consumer.setName("Consumer " + i);
consumer.start();
}
}
}
class Producer implements Runnable {
Queue<String> mSharedTasks;
int taskCount = 1;
public Producer(Queue<String> mSharedTasks) {
super();
this.mSharedTasks = mSharedTasks;
}
#Override
public void run() {
while (true) {
synchronized (mSharedTasks) {
try {
if (mSharedTasks.size() == ProducerConsumerProblem.CAPACITY) {
System.out.println("Producer Waiting!!");
mSharedTasks.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
while (mSharedTasks.size() != ProducerConsumerProblem.CAPACITY) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
}
String produceHere = Thread.currentThread().getName()
+ "_Item number_" + taskCount++;
synchronized (mSharedTasks) {
mSharedTasks.add(produceHere);
System.out.println(produceHere);
if (mSharedTasks.size() == 1) {
mSharedTasks.notifyAll(); // Informs consumer that there
// is something to consume.
}
}
}
}
}
}
class Consumer implements Runnable {
Queue<String> mSharedTasks;
public Consumer(Queue<String> mSharedTasks) {
super();
this.mSharedTasks = mSharedTasks;
}
#Override
public void run() {
while (true) {
synchronized (mSharedTasks) {
if (mSharedTasks.isEmpty()) { // Checks whether there is no task
// to consume.
try {
mSharedTasks.wait(); // Waits for producer to produce!
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
while (!mSharedTasks.isEmpty()) { // Consumes till task list is
// empty
try {
// Consumer consumes late hence producer has to wait...!
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
synchronized (mSharedTasks) {
System.out.println(Thread.currentThread().getName()
+ " consumed " + mSharedTasks.poll());
if (mSharedTasks.size() == ProducerConsumerProblem.CAPACITY - 1)
mSharedTasks.notifyAll();
}
}
}
}
}
public class ProducerConsumerTest {
public static void main(String[] args) {
CubbyHole c = new CubbyHole();
Producer p1 = new Producer(c, 1);
Consumer c1 = new Consumer(c, 1);
p1.start();
c1.start();
}
}
class CubbyHole {
private int contents;
private boolean available = false;
public synchronized int get() {
while (available == false) {
try {
wait();
} catch (InterruptedException e) {
}
}
available = false;
notifyAll();
return contents;
}
public synchronized void put(int value) {
while (available == true) {
try {
wait();
} catch (InterruptedException e) {
}
}
contents = value;
available = true;
notifyAll();
}
}
class Consumer extends Thread {
private CubbyHole cubbyhole;
private int number;
public Consumer(CubbyHole c, int number) {
cubbyhole = c;
this.number = number;
}
public void run() {
int value = 0;
for (int i = 0; i < 10; i++) {
value = cubbyhole.get();
System.out.println("Consumer #"
+ this.number
+ " got: " + value);
}
}
}
class Producer extends Thread {
private CubbyHole cubbyhole;
private int number;
public Producer(CubbyHole c, int number) {
cubbyhole = c;
this.number = number;
}
public void run() {
for (int i = 0; i < 10; i++) {
cubbyhole.put(i);
System.out.println("Producer #" + this.number
+ " put: " + i);
try {
sleep((int) (Math.random() * 100));
} catch (InterruptedException e) {
}
}
}
}