Random result on more threads in the Replicated Workers Paradigm - java

My code is the following:
WorkPool.java
import java.util.LinkedList;
/**
* Class that implements a work pool based on the model of "replicated workers"
* Tasks introduced in the work pool are objects of type MRCTask
*
*/
public class WorkPool {
int nThreads; //total number of worker threads
int nWaiting = 0; //number of worker threads blocked waiting for a task
public boolean ready = false; //problem is finished
LinkedList<MRCTask> tasks = new LinkedList<MRCTask>();
/**
* Constructor for class WorkPool.
* #param nThreads - number of worker threads
*/
public WorkPool(int nThreads) {
this.nThreads = nThreads;
}
/**
* Function which tries to obtain a task from the work pool
* If there are not available tasks, the function hangs until
* a task can be given or until the problem is finished
* #return A task to solve or null if the problem is finished
*/
public synchronized MRCTask getWork() {
if (tasks.size() == 0) { //empty work pool
nWaiting++;
/*
* finish condition:
* there is no available task in the work pool and no worker
* is active
*/
if (nWaiting == nThreads) {
ready = true;
/* problem is finished, announcing all workers */
notifyAll();
return null;
} else {
while (!ready && tasks.size() == 0) {
try {
this.wait();
} catch(Exception e) {e.printStackTrace();}
}
if (ready)
/* work is done */
return null;
nWaiting--;
}
}
return tasks.remove();
}
/**
* Function which inserts a task in the work pool
* #param sp The task which must be introduced
*/
synchronized void putWork(MRCTask sp) {
tasks.add(sp);
/* announcing one of the waiting workers */
this.notify();
}
}
TestMain.Java
public class TestMain {
public static void main(String[] args) throws InterruptedException {
int nr_proc = Runtime.getRuntime().availableProcessors();
WorkPool wp = new WorkPool(nr_proc);
MRCTask.t = 0;
for(int i = 0; i < 10000; i++)
wp.putWork(new MRCTask());
Worker[] wrk = new Worker[nr_proc];
for(int i = 0; i < nr_proc; i++)
wrk[i] = new Worker(wp);
for(int i = 0; i < nr_proc; i++)
wrk[i].start();
for(int i = 0; i < nr_proc; i++)
wrk[i].join();
System.out.println(MRCTask.t);
}
}
class Worker extends Thread {
WorkPool wp;
public Worker(WorkPool wp) {
this.wp = wp;
}
void work(MRCTask ps) throws Exception {
ps.processTask();
}
public void run() {
while (true) {
MRCTask ps = wp.getWork();
if (ps == null)
break;
try {
work(ps);
} catch (Exception e) {
e.printStackTrace();
System.exit(0);
}
}
}
}
class MRCTask {
static int t;
public void processTask() {
t += 5;
}
}
When running this code, I normally expect to get 50000 as the answer. That only happens when nr_proc is 1. When nr_proc is 2 or 4(in my case, availableProcessor() returns 4), I get random values, like 49960, 49900, 49995 and sometimes even 50000.
Could you please tell me what is wrong?
Thanks in advance and sorry for this huge code!
PS: I have tried to modify the function processTask() as it follows:
public void processTask() {
synchronized(this) {
t += 5;
}
}
but, I still get same problem. I thought having synchronized portions would help, but they don't.

Your value t is static. So the way you tried to synchronize things, it was doomed to failure. You actually didn't synchronize anything because you have many different MRCTask instances (10000 in fact). Each one of them has a separate lock/monitor.
Try changing your code in MRCTask to this:
private static final Object LOCK = new Object();
public void processTask() {
synchronized (LOCK) {
t += 5;
}
}
This is different, now you use a shared lock.
See if you still get unpredictable/random results. You won't.
Previously you were just having a classical race condition.

Related

Threading in Sequence

I am trying to learn how to write a program which performs a given set of tasks in sequence with the help of threads. For example, Writing a program which have 3 different threads print 1111…, 22222…., 333333……, so that the output will be 1,2,3,1,2,3,1,2,3…..? OR for e.g. 2 threads one is printing odd numbers and other even numbers, but the output should be printed in sequence - i.e. one even and then odd.
I would like to learn how to write similar kind of programs in which different threads print different stuff concurrently and the output should be printed in sequence.
What is the basic concept in writing these programs. Can we use ThreadPools/Executors for the purpose ? For e.g. can we use
ExecutorService exectorService = Executors.newFixedThreadPool(3);
Can we use Future, FurtureTask, Callable, execute, submit ...? I know these concepts but I am not able to connect the dots for solving the above scenarios.
Please guide me how to go about writing these kind of programs using multithreading / concurrency.
I have written a program using wait()/notifyAll(). Following is the program. I am not executing the consumer as I am printing the whole sequence at the end. Also I am limiting the capacity of the queue to be 15. So I am basically printing the odd / even range till 15.
public class ProduceEven implements Runnable {
private final List<Integer> taskQueue;
private final int MAX_CAPACITY;
public ProduceEven (List<Integer> sharedQueue, int size) {
this.taskQueue = sharedQueue;
this.MAX_CAPACITY = size;
}
#Override
public void run() {
// TODO Auto-generated method stub
int counter = 0;
while (counter < 15) {
try {
produce(counter++);
} catch (InterruptedException e) {
e.getMessage();
}
}
}
private void produce (int i) throws InterruptedException {
synchronized (taskQueue) {
while (taskQueue.size() == MAX_CAPACITY) {
System.out.println("Queue is full : "+Thread.currentThread().getName()+" is waiting , size: "+ taskQueue.size());
taskQueue.wait();
}
Thread.sleep(1000);
if(i%2==0) {
taskQueue.add(i);
}
taskQueue.notifyAll();
}
}
}
public class ProduceOdd implements Runnable {
private final List<Integer> taskQueue;
private final int MAX_CAPACITY;
public ProduceOdd (List<Integer> sharedQueue, int size) {
this.taskQueue = sharedQueue;
this.MAX_CAPACITY = size;
}
#Override
public void run() {
int counter = 0;
while (counter < 15) {
try {
produce(counter++);
} catch (InterruptedException e) {
e.getMessage();
}
}
}
private void produce (int i) throws InterruptedException {
synchronized (taskQueue) {
while (taskQueue.size() == MAX_CAPACITY) {
System.out.println("Queue is full : "+Thread.currentThread().getName()+" is waiting , size: "+ taskQueue.size());
taskQueue.wait();
}
Thread.sleep(1000);
if(i%2==1) {
taskQueue.add(i);
}
taskQueue.notify();
}
}
}
public class OddEvenExampleWithWaitAndNotify {
public static void main(String[] args) {
List<Integer> taskQueue = new ArrayList<Integer>();
int MAX_CAPACITY = 15;
Thread tProducerEven = new Thread(new ProduceEven(taskQueue, MAX_CAPACITY), "Producer Even");
Thread tProducerOdd = new Thread(new ProduceOdd(taskQueue, MAX_CAPACITY), "Producer Odd");
tProducerEven.start();
tProducerOdd.start();
try {
tProducerEven.join();
tProducerOdd.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
ListIterator listIterator = taskQueue.listIterator();
System.out.println("Elements Are:: ");
while(listIterator.hasNext()) {
System.out.print(listIterator.next()+" ");
}
}
}
The output which I get is: Elements Are:: 02134657911810131214
The output is all jumbled up. Why is it not in sequence. 01234567891011121314 What am I missing. I would be now trying to make the program using Semaphores. Also how do we make this program using explicit locks?
Yes, you can use ExecutorService as a starting point to run your threads. You can also create and start your Threads manually, that would make no difference.
The important thing is that your Threads will run in parallel if you do not synchronize them (i.e., they have to wait for one another). To synchronize you can, e.g. use Semaphores or other thread communication mechanisms.
You wrote in the comments you have written a producer/consumer program. It's a bit of the same thing. Each time the 1-Thread produces a 1, the 2-Thread must know that it can now produce a 2. When it is finished, it must let the 3-Thread know that it must produce a 3. The basic concepts are the same. Just the threads have both producer and consumer roles.
Hi this is one sample program to print Odd and Even using two thread and using thread synchronization among them.
Also we have used Executor framework which is not mandatory, you can create thread using new Thread() as well. For quick prototype I have used system.exit() which can be replaced with graceful shutdown of threads like, interruption and all.
package com.ones.twos.threes;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class OnesTwos {
public static void main(String[] args) {
BlockingQueue<Integer> bq1 = new ArrayBlockingQueue<Integer>(100);
BlockingQueue<Integer> bq2 = new ArrayBlockingQueue<Integer>(100);
ExecutorService executorService = Executors.newFixedThreadPool(2);
try {
bq1.put(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
executorService.submit(new OddEven(bq1, bq2));
executorService.submit(new OddEven(bq2, bq1));
executorService.shutdown();
}
public static class OddEven implements Runnable {
BlockingQueue<Integer> bq1;
BlockingQueue<Integer> bq2;
public OddEven(BlockingQueue<Integer> bq1, BlockingQueue<Integer> bq2) {
this.bq1 = bq1;
this.bq2 = bq2;
}
#Override
public void run() {
while (true) {
try {
int take = bq1.take();
System.out.println(take);
bq2.offer(take + 1);
if (take > 20)
System.exit(0);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
Mycode is also similar to Anirban's, except I am not using executor framework,
public class TestThread {
public static void main(String[] args) {
Boolean bol = new Boolean(true);
(new Thread(new Odd(bol), "odd")).start();
(new Thread(new Even(bol), "even")).start();
}
}
public class Even implements Runnable {
private Boolean flag;
public Even(Boolean b) {
this.flag = b;
}
#Override
public void run() {
for (int i = 2; i < 20; i = i + 2) {
synchronized (flag) {
try {
System.out.println(Thread.currentThread().getName()+":"+i);
Thread.sleep(1000);
flag.notify();
flag.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
public class Odd implements Runnable {
private Boolean flag;
public Odd(Boolean b) {
this.flag = b;
}
#Override
public void run() {
for (int i = 1; i < 20; i = i + 2) {
synchronized (flag) {
try {
System.out.println(Thread.currentThread().getName()+":"+i);
Thread.sleep(1000);
flag.notify();
flag.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
By establishing the thread pool of 3 (ExecutorService exectorService = Executors.newFixedThreadPool(3); you are essentilly limiting the executor capacity to 3 and other incoming threads will be on hold. If you want to run them in paralel you can just submit them at once. If you want to wait for each other and want to find out the result I suggest you use Callable. Personally I really like Callable because after submiting it you can just call the get method of Future, wait for a returned value from the executed thread and then continue to the next one. From the API you can see this:
/**
* Submits a value-returning task for execution and returns a
* Future representing the pending results of the task. The
* Future's {#code get} method will return the task's result upon
* successful completion.
*
*
* If you would like to immediately block waiting
* for a task, you can use constructions of the form
* {#code result = exec.submit(aCallable).get();}
And a very good example here. If you go for the Callable alternative then you don't need a Thread pool. Just a normal executor is fine. Remember to shut the executor down in the end.
class MyNumber {
int i = 1;
}
class Task implements Runnable {
MyNumber myNumber;
int id;
Task(int id, MyNumber myNumber) {
this.id = id;
this.myNumber = myNumber;
}
#Override
public void run() {
while (true) {
synchronized (myNumber) {
while (myNumber.i != id) {
try {
myNumber.wait(); //Wait until Thread with correct next number
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(id);
if (myNumber.i == 1) {
myNumber.i = 2;
} else if (myNumber.i == 2) {
myNumber.i = 3;
} else {
myNumber.i = 1;
}
myNumber.notifyAll();
}
}
}
}
In main method:
MyNumber myNumber = new MyNumber();
new Thread(new Task(1, myNumber)).start();
new Thread(new Task(2, myNumber)).start();
new Thread(new Task(3, myNumber)).start();
Hi here we have used 2 thread one to print even and another to print odd.
Both are separate and have no relation to each other.
But we have to do a synchronization mechanism between them. Also we need a mechanism to let the ball rolling, i.e. start one thread printing.
Each thread is waiting on condition and after doing it's task it lets other thread work and put ownself in waiting state.
Well happy path works fine, but we need special care when even thread is not in waiting state and the signal() from main fires, in that case even thread will never able to wake up and the program hangs.
So to make sure main thread successfully sends a signal() to even thread and even thread does not miss that we have used Phaser(with party) and checking even thread state in while loop in main.
Code is as below.
package com.ones.twos.threes;
import java.util.concurrent.Phaser;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class OnesTwosTrial2 {
public static void main(String[] args) {
Lock lk = new ReentrantLock();
Phaser ph = new Phaser(3); // to let main start the even thread
Condition even = lk.newCondition();
Condition odd = lk.newCondition();
OnesTwosTrial2 onestwostrial2 = new OnesTwosTrial2();
Thread ev = onestwostrial2.new Evens(lk, even, odd, ph);
Thread od = onestwostrial2.new Odds(lk, even, odd, ph);
ev.start();
od.start();
System.out.println("in main before arrive");
ph.arriveAndAwaitAdvance();
System.out.println("in main after arrive");
// we have to make sure odd and even thread is
// started and waiting on respective condition.
// So we used Phaser with 3, because we are having here
// 3 parties (threads)
// main, odd,even. We will signal only when all the
// threads have started.
// and waiting on conditions.
while (!Thread.State.WAITING.equals(ev.getState())) {
System.out.println("waiting");
}
lk.lock();
even.signal();
lk.unlock();
}
class Evens extends Thread {
Lock lk;
Condition even;
Condition odd;
Phaser ph;
public Evens(Lock lk, Condition even, Condition odd, Phaser ph) {
this.lk = lk;
this.even = even;
this.odd = odd;
this.ph = ph;
}
#Override
public void run() {
System.out.println("even ph");
int cnt = 0;
while (cnt < 20) {
try {
lk.lock();
ph.arrive();
even.await();
System.out.println(cnt);
cnt += 2;
odd.signal();
lk.unlock();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Odds extends Thread {
Lock lk;
Condition even;
Condition odd;
Phaser ph;
public Odds(Lock lk, Condition even, Condition odd, Phaser ph) {
this.lk = lk;
this.even = even;
this.odd = odd;
this.ph = ph;
}
#Override
public void run() {
System.out.println("odd ph");
int cnt = 1;
while (cnt < 20) {
try {
lk.lock();
ph.arrive();
odd.await();
System.out.println(cnt);
cnt += 2;
even.signal();
lk.unlock();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}

Can't understand barrier code

I ran across this barrier code and I cannot understand the barrierPost method.
Im supposed to use this code to solve an exercise where two teams of threads race eachother to count to 10000.
I don't understand why the same condition has different results which are opposite
public class Barrier {
private int currentPosters = 0, totalPosters = 0;
private int passedWaiters = 0, totalWaiters = 1;
/**
* #param totalPosters - Nr of threads required to start the waiting threads
* #param totalWaiters - Nr of threads started later
*/
public Barrier (int totalPosters, int totalWaiters) {
this.totalPosters = totalPosters;
this.totalWaiters = totalWaiters;
}
public synchronized void init(int i) {
totalPosters = i; currentPosters=0;
}
public synchronized void barrierSet(int i) {
totalPosters = i; currentPosters=0;
}
public synchronized void barrierWait() {
boolean interrupted = false;
while (currentPosters = totalPosters) {
try {wait();}
catch (InterruptedException ie) {interrupted=true;}
}
passedWaiters++;
if (passedWaiters == totalWaiters) {
currentPosters = 0; passedWaiters = 0; notifyAll();
}
if (interrupted) Thread.currentThread().interrupt();
}
public synchronized void barrierPost() {
boolean interrupted = false; // In case a poster thread beats barrierWait, keep count of posters.
while (currentPosters == totalPosters) {
try {wait();}
catch (InterruptedException ie) {interrupted=true;}
}
currentPosters++;
if (currentPosters == totalPosters) notifyAll();
if (interrupted) Thread.currentThread().interrupt();
}
}
Can someone help?

Java Threads (Race Condition)

I have doubt in the following piece of code. In this i expect race condition to occur for both the static variables 'a' and 'b' and the expect the output for both the variables to be less than 1000. However, the expected behaviour is not observed when i execute the below code as shown i.e. the output for b is always 1000. But, when i uncomment the lines marked with arrows and execute the below code, the race condition is observed for both the variables i.e the output for both the variables 'a' and 'b' is less than 1000. Need help with the same. Pardon me if i have missed out or ignored any of the basic or elementary concepts of threading considering the fact that i am still a newbie to java threads !!!
public class SampleRace {
public static void main(String[] args) {
// TODO Auto-generated method stub
SampleRace1 a = new SampleRace1();
SampleRace1 b = new SampleRace1();
Thread t1 = new Thread(a);
Thread t2 = new Thread(b);
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//System.out.println(SamapleLoop.a); // <---------------------
System.out.println(SampleRace1.b);
}
}
class SamapleLoop {
public static int a = 0;
public static void loop() {
a++;
}
}
class SampleRace1 implements Runnable {
public static int b = 0;
#Override
public void run() {
// TODO Auto-generated method stub
for (int i = 1; i <= 500; i++) {
//SamapleLoop.loop(); // <------------------------
b++;
}
}
}
Try increasing 500 to a 500.000.000, or doing more complex operations inside the loop. There's a chance that thread a is running to completion before thread b is even started - so they end up running in sequence, rather than in parallel.
You can also call Thread.yield every few cycles to give up your timeslice and let the other thread run.
If you want I can suggest a more proper race condition you can work on
import java.util.concurrent.atomic.AtomicInteger;
/*
* author: Atom Karinca
*/
/*
* Run this program multiple times to see the output.
* How does the result vary? Why does that happen?
*
*/
class Racer extends Thread {
private static final int NUM_ITERS = 1000000;
public void run() {
for(int j = 0; j < NUM_ITERS; j++) {
RaceCondition.sum();
}
}
}
public class RaceCondition {
public static long sum = 0;
// What happens when you make this method "synchronized"?
// Do you still see the bug?
//synchronized
public static void sum() {
sum = sum + 1;
}
public static void main(String[] args) throws InterruptedException {
Racer leftAdder = new Racer();
Racer rightAdder = new Racer();
leftAdder.start();
rightAdder.start();
// wait for the threads to finish
leftAdder.join();
rightAdder.join();
System.out.println("Sum: " + sum);
}
}

Google App Engine Modules + HttpServlet with static values;

I am developing an application that delivers notifications to android and iOS devices. I am using basic scaling and have implemented logic (modifying this example) so an appropriate number of workers are active at a given time without using a resident instance.
public class NotificationWorkerServlet extends HttpServlet {
/**
*
*/
private static final long serialVersionUID = 1L;
private static final Logger log = Logger
.getLogger(NotificationWorkerServlet.class.getName());
private static final int MAX_WORKER_COUNT = 5;
private static final int MILLISECONDS_TO_WAIT_WHEN_NO_TASKS_LEASED = 2500;
private static final int TEN_MINUTES = (10 * 60 * 1000);
// Area of concern
private static SyncCounter counter;
/**
* Used to keep number of running workers in sync
*/
private class SyncCounter {
private int c = 0;
public SyncCounter(){
log.info("Sync counter instantiated");
}
public synchronized void increment() {
c++;
log.info("Increment sync counter, workers:" + c);
}
public synchronized void decrement() {
c--;
log.info("Decrement sync counter, workers:" + c);
}
public synchronized int value() {
return c;
}
}
/**
* Call made from module when notification was added to task queue
*/
#Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
super.doPost(req, resp);
// Instantiate counter with first call
if(counter == null){
counter = new SyncCounter();
}
log.info("Starting to build workers");
for (int workerNo = counter.value(); workerNo < MAX_WORKER_COUNT; workerNo++) {
log.info("Starting thread for worker: " + workerNo);
// Get the current queue to check it's statistics
Queue notificationQueue = QueueFactory
.getQueue("notification-delivery");
if (notificationQueue.fetchStatistics().getNumTasks() > 30 * workerNo) {
counter.increment();
Thread thread = ThreadManager
.createBackgroundThread(new Runnable() {
#Override
public void run() {
try {
doPolling();
} catch (Exception e) {
e.printStackTrace();
}
}
});
thread.start();
} else {
break; // Current number of threads is sufficient.
}
}
resp.setStatus(HttpServletResponse.SC_OK);
}
/**
* poll the task queue and lease the tasks
*
* Wait for up to 10 minutes for tasks to be added to queue before killing
* tasks
*
*/
private void doPolling() {
log.info("Doing pulling");
try {
int loopsWithoutProcessedTasks = 0;
Queue notificationQueue = QueueFactory
.getQueue("notification-delivery");
NotificationWorker worker = new NotificationWorker(
notificationQueue);
while (!LifecycleManager.getInstance().isShuttingDown()) {
boolean tasksProcessed = worker.processBatchOfTasks();
ApiProxy.flushLogs();
if (!tasksProcessed) {
log.info("waiting for tasks");
// Wait before trying to lease tasks again.
try {
loopsWithoutProcessedTasks++;
// If worker hasn't had any tasks for 30 min, kill it.
if (loopsWithoutProcessedTasks >= (TEN_MINUTES / MILLISECONDS_TO_WAIT_WHEN_NO_TASKS_LEASED)) {
break;
} else {
// Else, wait and try again (to avoid tearing down
// useful Notification Senders)
Thread.sleep(MILLISECONDS_TO_WAIT_WHEN_NO_TASKS_LEASED);
}
} catch (InterruptedException e) {
log.info("Notification worker thread interrupted");
break;
}
} else {
log.info("processed batch of tasks");
loopsWithoutProcessedTasks = 0;
}
}
} catch (Exception e) {
log.warning("Exception caught and handled in notification worker: "
+ e.getLocalizedMessage());
} finally {
counter.decrement();
}
log.info("Instance is shutting down");
}
}
In a controlled testing scenario, it works just fine. However, I know static, mutable values are bad news in servlets where multiple users could potentially be connecting at the same time.
Has anyone done something similar and had issues with pushing multiple notifications to the same device, lost tasks or had idle tasks burning a hole in the bank?

Equivalent of Go channel in Java

I have a requirement where I need to read from a set of Blocking queues. The blocking queues are created by the Library I am using. My code has to read from the queues. I don't want to create a reader thread for each of these blocking queues. Rather I want to poll them for availability of data using a single thread (or probably using 2/3 threads at max). As some of the blocking queues might not have data for long time, while some of them may get bursts of data. Polling the queues with small timeout will work, but that is not efficient at all as it still needs to keep looping over all the queues even when some of them are without data for long time. Basically, I am looking for a select/epoll(used on sockets) kind of mechanism on blocking queues. Any clue is really appreciated.
Doing that in Go is real easy though. Below code simulates the same with channels and goroutines:
package main
import "fmt"
import "time"
import "math/rand"
func sendMessage(sc chan string) {
var i int
for {
i = rand.Intn(10)
for ; i >= 0 ; i-- {
sc <- fmt.Sprintf("Order number %d",rand.Intn(100))
}
i = 1000 + rand.Intn(32000);
time.Sleep(time.Duration(i) * time.Millisecond)
}
}
func sendNum(c chan int) {
var i int
for {
i = rand.Intn(16);
for ; i >= 0; i-- {
time.Sleep(20 * time.Millisecond)
c <- rand.Intn(65534)
}
i = 1000 + rand.Intn(24000);
time.Sleep(time.Duration(i) * time.Millisecond)
}
}
func main() {
msgchan := make(chan string, 32)
numchan := make(chan int, 32)
i := 0
for ; i < 8 ; i++ {
go sendNum(numchan)
go sendMessage(msgchan)
}
for {
select {
case msg := <- msgchan:
fmt.Printf("Worked on %s\n", msg)
case x := <- numchan:
fmt.Printf("I got %d \n", x)
}
}
}
I suggest you look into using the JCSP library. The equivalent of Go's select is called Alternative. You would only need one consuming thread, which will not need to poll the incoming channels if it switches on them with Alternative. Therefore this would be an efficient way to multiplex the source data.
It will help a lot if you are able to replace the BlockingQueues with JCSP channels. Channels behave essentially the same but provide a greater degree of flexibility regarding the fan-out or fan-in of sharing of channel ends, and in particular, the use of channels with Alternative.
For an example of usage, here is a fair multiplexer. This example demonstrates a process that fairly multiplexes traffic from its array of input channels to its single output channel. No input channel will be starved, regardless of the eagerness of its competitors.
import org.jcsp.lang.*;
public class FairPlex implements CSProcess {
private final AltingChannelInput[] in;
private final ChannelOutput out;
public FairPlex (final AltingChannelInput[] in, final ChannelOutput out) {
this.in = in;
this.out = out;
}
public void run () {
final Alternative alt = new Alternative (in);
while (true) {
final int index = alt.fairSelect ();
out.write (in[index].read ());
}
}
}
Note that if priSelect were used above, higher-indexed channels would be starved if lower-indexed channels were continually demanding service. Or instead of fairSelect, select could be used, but then no starvation analysis is possible. The select mechanism should only be used when starvation is not an issue.
Freedom from Deadlock
As with Go, a Java program using channels must be designed not to deadlock. The implementation of low-level concurrency primitives in Java is very hard to get right and you need something dependable. Fortunately, Alternative has been validated by formal analysis, along with the JCSP channels. This makes it a solid reliable choice.
Just to clear up on slight point of confusion, the current JCSP version is 1.1-rc5 in the Maven repos, not what the website says.
An another choice is here for Java6+
A BlockingDeque implementation class:
import java.lang.ref.WeakReference;
import java.util.WeakHashMap;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.atomic.AtomicLong;
class GoChannelPool {
private final static GoChannelPool defaultInstance = newPool();
private final AtomicLong serialNumber = new AtomicLong();
private final WeakHashMap<Long, WeakReference<GoChannel>> channelWeakHashMap = new WeakHashMap<>();
private final LinkedBlockingDeque<GoChannelObject> totalQueue = new LinkedBlockingDeque<>();
public <T> GoChannel<T> newChannel() {
GoChannel<T> channel = new GoChannel<>();
channelWeakHashMap.put(channel.getId(), new WeakReference<GoChannel>(channel));
return channel;
}
public void select(GoSelectConsumer consumer) throws InterruptedException {
consumer.accept(getTotalQueue().take());
}
public int size() {
return getTotalQueue().size();
}
public int getChannelCount() {
return channelWeakHashMap.values().size();
}
private LinkedBlockingDeque<GoChannelObject> getTotalQueue() {
return totalQueue;
}
public static GoChannelPool getDefaultInstance() {
return defaultInstance;
}
public static GoChannelPool newPool() {
return new GoChannelPool();
}
private GoChannelPool() {}
private long getSerialNumber() {
return serialNumber.getAndIncrement();
}
private synchronized void syncTakeAndDispatchObject() throws InterruptedException {
select(new GoSelectConsumer() {
#Override
void accept(GoChannelObject t) {
WeakReference<GoChannel> goChannelWeakReference = channelWeakHashMap.get(t.channel_id);
GoChannel channel = goChannelWeakReference != null ? goChannelWeakReference.get() : null;
if (channel != null) {
channel.offerBuffer(t);
}
}
});
}
class GoChannel<E> {
// Instance
private final long id;
private final LinkedBlockingDeque<GoChannelObject<E>> buffer = new LinkedBlockingDeque<>();
public GoChannel() {
this(getSerialNumber());
}
private GoChannel(long id) {
this.id = id;
}
public long getId() {
return id;
}
public E take() throws InterruptedException {
GoChannelObject object;
while((object = pollBuffer()) == null) {
syncTakeAndDispatchObject();
}
return (E) object.data;
}
public void offer(E object) {
GoChannelObject<E> e = new GoChannelObject();
e.channel_id = getId();
e.data = object;
getTotalQueue().offer(e);
}
protected void offerBuffer(GoChannelObject<E> data) {
buffer.offer(data);
}
protected GoChannelObject<E> pollBuffer() {
return buffer.poll();
}
public int size() {
return buffer.size();
}
#Override
protected void finalize() throws Throwable {
super.finalize();
channelWeakHashMap.remove(getId());
}
}
class GoChannelObject<E> {
long channel_id;
E data;
boolean belongsTo(GoChannel channel) {
return channel != null && channel_id == channel.id;
}
}
abstract static class GoSelectConsumer{
abstract void accept(GoChannelObject t);
}
}
then we can use it in this way:
GoChannelPool pool = GoChannelPool.getDefaultInstance();
final GoChannelPool.GoChannel<Integer> numberCh = pool.newChannel();
final GoChannelPool.GoChannel<String> stringCh = pool.newChannel();
final GoChannelPool.GoChannel<String> otherCh = pool.newChannel();
ExecutorService executorService = Executors.newCachedThreadPool();
int times;
times = 2000;
final CountDownLatch countDownLatch = new CountDownLatch(times * 2);
final AtomicInteger numTimes = new AtomicInteger();
final AtomicInteger strTimes = new AtomicInteger();
final AtomicInteger defaultTimes = new AtomicInteger();
final int finalTimes = times;
executorService.submit(new Runnable() {
#Override
public void run() {
for (int i = 0; i < finalTimes; i++) {
numberCh.offer(i);
try {
Thread.sleep((long) (Math.random() * 10));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
executorService.submit(new Runnable() {
#Override
public void run() {
for (int i = 0; i < finalTimes; i++) {
stringCh.offer("s"+i+"e");
try {
Thread.sleep((long) (Math.random() * 10));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
int otherTimes = 3;
for (int i = 0; i < otherTimes; i++) {
otherCh.offer("a"+i);
}
for (int i = 0; i < times*2 + otherTimes; i++) {
pool.select(new GoChannelPool.GoSelectConsumer() {
#Override
void accept(GoChannelPool.GoChannelObject t) {
// The data order should be randomized.
System.out.println(t.data);
countDownLatch.countDown();
if (t.belongsTo(stringCh)) {
strTimes.incrementAndGet();
return;
}
else if (t.belongsTo(numberCh)) {
numTimes.incrementAndGet();
return;
}
defaultTimes.incrementAndGet();
}
});
}
countDownLatch.await(10, TimeUnit.SECONDS);
/**
The console output of data should be randomized.
numTimes.get() should be 2000
strTimes.get() should be 2000
defaultTimes.get() should be 3
*/
and beware that the select works only if the channels belong to the same GoChannelPool, or just use the default GoChannelPool(however the performance would be lower if too many channels share the same GoChannelPool)
The only way is to replace standard queues with objects of a more functional class, which notifies consumer(s) when datum is inserted in an empty queue. This class still can implement the BlockingQueue interface, so the other side (producer) see no difference. The trick is that put operation should also raise a flag and notify consumer. Consumer, after polling all threads, clears the flag and calls Object.wait().
I remember when I was very new to Java, not knowing threads could share the memory of the process, I would have my threads communicate using (TCP/local) Sockets. Perhaps this can also work.

Categories

Resources