How do I implement an ArrayBlockingQueue? - java

The code below is the classic Producer/Consumer problem.
The code runs fine, but is still very tedious to use. I need to implement an ArrayBlockingQueue, but I am unsure on how to do so in order for the program to become threadsafe.
Any help would be greatly appreciated.
import java.util.LinkedList;
import java.util.Queue;
public class ProducerConsumer{
private static int NUM_MESSAGES = 3;
private static int NUM_PRODUCERS = 5;
private static int NUM_CONSUMERS = 5;
public static void main(String[] args) throws InterruptedException{
Queue<String> buffer = new LinkedList<String>();
Thread[] producers = new Thread[NUM_PRODUCERS];
for(int i=0; i<NUM_PRODUCERS; i++){
producers[i] = new Producer("producer"+i, buffer);
producers[i].start();
}
Thread[] consumers = new Thread[NUM_CONSUMERS];
for(int i=0; i<NUM_CONSUMERS; i++){
consumers[i] = new Consumer("consumer"+i, buffer);
consumers[i].start();
}
for(int i=0; i<NUM_PRODUCERS; i++){
producers[i].join();
}
for(int i=0; i<NUM_CONSUMERS; i++){
consumers[i].join();
}
System.err.println("messages left in buffer:");
while(!buffer.isEmpty()){
System.err.println(buffer.remove());
}
}
public static class Producer extends Thread{
Queue<String> buffer;
public Producer(String name, Queue<String> newBuffer){
super(name);
buffer = newBuffer;
}
public void run(){
for (int i=0; i<NUM_MESSAGES; i++){
String message = "message "+i+" from thread "+getName();
buffer.add(message);
System.err.println("sent "+message);
try{
Thread.sleep((long)(Math.random()*10));
}catch(InterruptedException e){}
}
}
}
public static class Consumer extends Thread{
Queue<String> buffer;
public Consumer(String name, Queue<String> newBuffer){
super(name);
buffer = newBuffer;
}
public void run(){
int count = 0;
while (count < NUM_MESSAGES){
String message;
if(!buffer.isEmpty()){
message = buffer.remove();
System.err.println(getName()+" received "+message);
count++;
}
try{
Thread.sleep((long)(Math.random()*10));
}catch(InterruptedException e){}
}
}
}
}

Related

Make a parallel process by modifying my original code as little as possible

I have this class:
package metodo_java8_moderno;
import java.util.ArrayList;
import java.util.List;
public class SingleThreadClass {
public List<Object> editAndAdd(List<List<Long>> matrix){
Long limit = (long) matrix.get(0).size()*matrix.size()/2;
List<Long> numbers = new ArrayList<>();
for(int i=0; i<matrix.get(0).size(); i++){
for(int j=0; j<matrix.size(); j++){
if(matrix.get(j).get(i).longValue() <= limit){
numbers.add(matrix.get(j).get(i));
matrix.get(j).set(i,null);
}
}
}
List<Object> objectList = new ArrayList<>();
objectList.add(matrix);
objectList.add(numbers);
return objectList;
}
}
I want to parallel only the following piece by exploiting all the cores of my CPU:
for(int j=0; j<matrix.size(); j++){
if(matrix.get(j).get(i).longValue() <= limit){
numbers.add(matrix.get(j).get(i));
matrix.get(j).set(i,null);
}
}
I get an error and I believe it is due to the sharing of objects between different threads.
I post all the code of my work:
ElementMutator.java
package metodo_java8_moderno;
#FunctionalInterface
public interface ElementMutator<T> {
void apply(int i);
}
ForkJoinListMutator.java
package metodo_java8_moderno;
import java.util.List;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveAction;
public class ForkJoinListMutator {
public static final int DEFAULT_SEQ_THRESHOLD = 10000;
private static final ForkJoinListMutator defaultInstance = new ForkJoinListMutator(ForkJoinPool.commonPool());
private final ForkJoinPool forkJoinPool;
public ForkJoinListMutator(ForkJoinPool forkJoinPool) {
this.forkJoinPool = forkJoinPool;
}
public static ForkJoinListMutator getDefault() {
return defaultInstance;
}
public <T> void mutate(List<T> list, ElementMutator<T> mutator) {
mutate(list, DEFAULT_SEQ_THRESHOLD, mutator);
}
public <T> void mutate(List<T> list, int seqThreshold, ElementMutator<T> mutator) {
MutateTask<T> mainTask = new MutateTask<>(list, seqThreshold, mutator);
forkJoinPool.invoke(mainTask);
}
private static class MutateTask<T> extends RecursiveAction {
private final List<T> list;
private final int start;
private final int end;
private final int seqThreshold;
private final ElementMutator<T> mutator;
public MutateTask(List<T> list, int seqThreshold, ElementMutator<T> mutator) {
this(list, 0, list.size(), seqThreshold, mutator);
}
public MutateTask(List<T> list, int start, int end, int seqThreshold, ElementMutator<T> mutator) {
this.list = list;
this.start = start;
this.end = end;
this.seqThreshold = seqThreshold;
this.mutator = mutator;
}
#Override
protected void compute() {
final int length = end - start;
if (length <= seqThreshold) {
computeSequentially();
} else {
MutateTask<T> leftTask = new MutateTask<>(list, start, start+length/2, seqThreshold, mutator);
leftTask.fork();
leftTask.join();
MutateTask<T> rightTask = new MutateTask<>(list, start+length/2, end, seqThreshold, mutator);
rightTask.compute();
}
}
private void computeSequentially() {
for (int i = start; i < end; i++) {
mutator.apply(i);
}
}
}
}
ForkJoinListMutatorExample.java
package metodo_java8_moderno;
import java.util.List;
public class ForkJoinListMutatorExample {
public static void main(String args[]) {
GenerateMatrix generateMatrix = new GenerateMatrix();
List<List<Long>> matrix = generateMatrix.generate(3,4);
System.out.println(matrix);
long t1 = System.nanoTime();
SingleThreadClass singleThreadClass = new SingleThreadClass();
List<Object> output = singleThreadClass.editAndAdd(matrix);
long t2 = System.nanoTime();
System.out.println("Time taken single thread process: " + (t2-t1)/100000000);
List<List<Long>> newMatrix = (List<List<Long>>) output.get(0);
List<Long> numbers = (List<Long>) output.get(1);
System.out.println(newMatrix);
System.out.println(numbers);
t1 = System.nanoTime();
MultiThreadClass multiThreadClass = new MultiThreadClass();
output = multiThreadClass.editAndAdd(matrix);
t2 = System.nanoTime();
System.out.println("Time taken multi thread process: " + (t2-t1)/100000000);
List<List<Long>> newMatrix2 = (List<List<Long>>) output.get(0);
List<Long> numbers2 = (List<Long>) output.get(1);
System.out.println(newMatrix2);
System.out.println(numbers2);
}
}
GenerateMatrix.java
package metodo_java8_moderno;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class GenerateMatrix {
public List<List<Long>> generate(int columns, int rows){
List<List<Long>> matrix = new ArrayList<>();
List<Long> row;
Random randomGenerator = new Random();
for(int i=0; i<rows; i++){
row = new ArrayList<>();
for(int j=0; j<columns; j++){
row.add((long) randomGenerator.nextInt(columns*rows+1));
}
matrix.add(row);
}
return matrix;
}
}
MultiThreadClass.java
package metodo_java8_moderno;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class MultiThreadClass {
private ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();
public List<List<Long>> matrix;
public void setMatrix(List<List<Long>> matrix) {
reentrantReadWriteLock.writeLock().lock();
try {
this.matrix = matrix;
} catch (Exception e){
this.matrix = null;
} finally {
reentrantReadWriteLock.writeLock().unlock();
}
}
public List<List<Long>> getMatrix() {
reentrantReadWriteLock.readLock().lock();
List<List<Long>> matrix;
try {
matrix = this.matrix;
} catch (Exception e){
matrix = null;
} finally {
reentrantReadWriteLock.readLock().unlock();
}
return matrix;
}
public int i;
public void setI(int i) {
reentrantReadWriteLock.writeLock().lock();
try {
this.i = i;
} catch (Exception e){
this.i = -1;
} finally {
reentrantReadWriteLock.writeLock().unlock();
}
}
public int getI() {
reentrantReadWriteLock.readLock().lock();
int i;
try {
i = this.i;
} catch (Exception e){
i = -1;
} finally {
reentrantReadWriteLock.readLock().unlock();
}
return i;
}
public List<Long> numbers;
public void setNumbers(List<Long> numbers) {
reentrantReadWriteLock.writeLock().lock();
try {
this.numbers = numbers;
} catch (Exception e){
this.numbers = null;
} finally {
reentrantReadWriteLock.writeLock().unlock();
}
}
public List<Long> getNumbers() {
reentrantReadWriteLock.readLock().lock();
List<Long> numbers;
try {
numbers = this.numbers;
} catch (Exception e){
numbers = null;
} finally {
reentrantReadWriteLock.readLock().unlock();
}
return numbers;
}
public Long limit;
public void setLimit(Long limit) {
reentrantReadWriteLock.writeLock().lock();
try {
this.limit = limit;
} catch (Exception e){
this.limit = null;
} finally {
reentrantReadWriteLock.writeLock().unlock();
}
}
public Long getLimit() {
reentrantReadWriteLock.readLock().lock();
Long limit;
try {
limit = this.limit;
} catch (Exception e){
limit = null;
} finally {
reentrantReadWriteLock.readLock().unlock();
}
return limit;
}
public List<Object> editAndAdd(List<List<Long>> matrix){
this.matrix = matrix;
this.limit = (long) this.matrix.get(0).size()*this.matrix.size()/2;
this.numbers = new ArrayList<>();
int core = Runtime.getRuntime().availableProcessors();
for(int i=0; i<this.matrix.get(0).size(); i++){
this.i = i;
ForkJoinListMutator listMutator = ForkJoinListMutator.getDefault();
listMutator.mutate(this.matrix,Math.max(1,this.matrix.size()/(core*1+1)),(j) -> parallelFor(j));
}
List<Object> objectList = new ArrayList<>();
objectList.add(this.matrix);
objectList.add(this.numbers);
return objectList;
}
public void parallelFor(int j){
try{
List<List<Long>> matrix = getMatrix();
int i = getI();
List<Long> numbers = getNumbers();
Long limit = getLimit();
if(matrix.get(j).get(i).longValue() <= limit){
numbers.add(matrix.get(j).get(i));
matrix.get(j).set(i,null);
}
setMatrix(matrix);
setI(i);
setNumbers(numbers);
setLimit(limit);
//System.out.println(">> "+this.matrix);
//System.out.println(">> "+this.numbers);
}catch (Exception e){
System.out.println("Errore!");
System.out.println(e.getMessage());
System.out.println(e.getCause());
}
}
}
SingleThreadClass.java
package metodo_java8_moderno;
import java.util.ArrayList;
import java.util.List;
public class SingleThreadClass {
public List<Object> editAndAdd(List<List<Long>> matrix){
Long limit = (long) matrix.get(0).size()*matrix.size()/2;
List<Long> numbers = new ArrayList<>();
for(int i=0; i<matrix.get(0).size(); i++){
for(int j=0; j<matrix.size(); j++){
if(matrix.get(j).get(i).longValue() <= limit){
numbers.add(matrix.get(j).get(i));
matrix.get(j).set(i,null);
}
}
}
List<Object> objectList = new ArrayList<>();
objectList.add(matrix);
objectList.add(numbers);
return objectList;
}
}

Not getting expected result when updating AtomicInteger variable in multiple threads

In this code I'm using 10 threads updating an AtomicInteger variable. I expect the final result of Counter.getInstance().holder.n to be 1000000, but it prints out random number like 991591.
What's wrong with my code?
public class Test {
public static void main(String[] args) {
List<Thread> list = new ArrayList<Thread>();
for (int i = 0; i < 10; i++) {
list.add(new Thread() {
public void run() {
for (int i = 0; i < 100000; i++) {
Counter.getInstance().holder.n.incrementAndGet();
}
}
});
}
for (Thread thread : list) {
thread.start();
}
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Counter.getInstance().holder.n);
}
}
class Counter {
private static Counter counter;
Holder holder = new Holder();
public static Counter getInstance() {
if (counter == null) {
counter = new Counter();
}
return counter;
}
class Holder {
AtomicInteger n = new AtomicInteger(0);
}
}
You have two major concurrent issues here:
You don't wait for every Thread to finish work correctly. There are multiple ways to achieve that, the simplest is to use Thread.join().
Your singleton implementation doesn't seem correct. I suppose you intended to implement it with an inner class. It seems that this answer can help to understand what's happening here.
Here is the implementation that seems more or less correct.
class Test {
public static void main(String[] args) throws InterruptedException {
List<Thread> list = new ArrayList<Thread>();
for (int i = 0; i < 10; i++) {
list.add(new Thread() {
public void run() {
for (int i = 0; i < 100000; i++) {
Counter.getInstance().n.incrementAndGet();
}
}
});
}
for (Thread thread : list) {
thread.start();
}
for (Thread thread : list) {
thread.join();
}
System.out.println(Counter.getInstance().n);
}
}
class Counter {
public AtomicInteger n = new AtomicInteger(0);
public static Counter getInstance() {
return Holder.instance;
}
private static class Holder {
private static final Counter instance = new Counter();
}
}
You can use something like CountDownLatch as well. For example:
final int count = 10;
CountDownLatch latch = new CountDownLatch(count);
List<Thread> list = new ArrayList<Thread>();
for (int i = 0; i < count; i++) {
list.add(new Thread() {
public void run() {
for (int i = 0; i < 100000; i++) {
Counter.getInstance().n.incrementAndGet();
}
latch.countDown();
}
});
}
for (Thread thread : list) {
thread.start();
}
latch.await();
System.out.println(Counter.getInstance().n);

How to consume in Producer-Consumer using Semphores?

I am trying out the Producer-Consumer problem using Semaphore. The program looks fine to me except for one place.
public class ProducerConsumerWithSemaphores
{
private final ArrayList<Integer> list = new ArrayList<>(5);
private final Semaphore semaphoreProducer = new Semaphore(1);
private final Semaphore semaphoreConsumer = new Semaphore(0);
private void produce() throws InterruptedException
{
for(int i = 0;i< 5;i++)
{
semaphoreProducer.acquire();
list.add(i);
System.out.println("Produced: " + i);
semaphoreConsumer.release();
}
}
private void consumer() throws InterruptedException
{
while (!list.isEmpty()) /// This line is where I have the doubt
{
semaphoreConsumer.acquire();
System.out.println("Consumer: " + list.remove(list.size()-1));
semaphoreProducer.release();
Thread.sleep(100);
}
}
public static void main(String[] args)
{
final ProducerConsumerWithSemaphores obj = new ProducerConsumerWithSemaphores();
new Thread(new Runnable()
{
#Override
public void run()
{
try
{
obj.produce();
} catch (InterruptedException e)
{
e.printStackTrace();
}
}
}).start();
new Thread(new Runnable()
{
#Override
public void run()
{
try
{
obj.consumer();
} catch (InterruptedException e)
{
e.printStackTrace();
}
}
}).start();
}
}
Is it okay to check the list if it is not empty before acquiring the semaphore? Will this cause any problem in multithreaded environment?
private void consumer() throws InterruptedException
{
while (!list.isEmpty()) /// This line is where I have the doubt
The problem is, if consumer runs faster than producer, your consumer quit immediately, then you have no consumer!!
The correct example looks like,
Producer–consumer problem#Using semaphores. I believe your intention is not to use true as endless loop because you want Producer/Consumer to quit when job is done. If that's your intention, you can 1. set a totalCount to end the loop. 2. Or a boolean flag which will be set by producer after putItemIntoBuffer when producer put the last one. The flag must be protected as well as the buffer.(update: this method doesn't work if there's multiple producers/consumers) 3. Simulate EOF ( idea taken from producer - consume; how does the consumer stop?)
Will this cause any problem in multithreaded environment?
Your critical section (your list) is not protected . Usually we use 3 semaphores. The 3rd one is used as a mutex to protect the buffer.
To stop producers/consumers,
Example code with method 1:
public class Test3 {
private Semaphore mutex = new Semaphore(1);
private Semaphore fillCount = new Semaphore(0);
private Semaphore emptyCount = new Semaphore(3);
private final List<Integer> list = new ArrayList<>();
class Producer implements Runnable {
private final int totalTasks;
Producer(int totalTasks) {
this.totalTasks = totalTasks;
}
#Override
public void run() {
try {
for (int i = 0; i < totalTasks; i++) {
emptyCount.acquire();
mutex.acquire();
list.add(i);
System.out.println("Produced: " + i);
mutex.release();
fillCount.release();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class Consumer implements Runnable {
private final int totalTasks;
Consumer(int totalTasks) {
this.totalTasks = totalTasks;
}
#Override
public void run() {
try {
for (int i = 0; i < totalTasks; i++) {
fillCount.acquire();
mutex.acquire();
int item = list.remove(list.size() - 1);
System.out.println("Consumed: " + item);
mutex.release();
emptyCount.release();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void runTest() {
int numProducer = 3;
int tasksPerProducer = 10;
int numConsumer = 6;
int tasksPerConsumer = 5;
for (int i = 0; i < numProducer; i++) {
new Thread(new Producer(tasksPerProducer)).start();
}
for (int i = 0; i < numConsumer; i++) {
new Thread(new Consumer(tasksPerConsumer)).start();
}
}
public static void main(String[] args) throws IOException {
Test3 t = new Test3();
t.runTest();
}
}
Example code with method 3:
public class Test4 {
private Semaphore mutex = new Semaphore(1);
private Semaphore fillCount = new Semaphore(0);
private Semaphore emptyCount = new Semaphore(3);
private Integer EOF = Integer.MAX_VALUE;
private final Queue<Integer> list = new LinkedList<>(); // need to put/get data in FIFO
class Producer implements Runnable {
private final int totalTasks;
Producer(int totalTasks) {
this.totalTasks = totalTasks;
}
#Override
public void run() {
try {
for (int i = 0; i < totalTasks + 1; i++) {
emptyCount.acquire();
mutex.acquire();
if (i == totalTasks) {
list.offer(EOF);
} else {
// add a valid value
list.offer(i);
System.out.println("Produced: " + i);
}
mutex.release();
fillCount.release();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class Consumer implements Runnable {
#Override
public void run() {
try {
boolean finished = false;
while (!finished) {
fillCount.acquire();
mutex.acquire();
int item = list.poll();
if (EOF.equals(item)) {
// do not consume this item because it means EOF
finished = true;
} else {
// it's a valid value, consume it.
System.out.println("Consumed: " + item);
}
mutex.release();
emptyCount.release();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void runTest() {
int numProducer = 3;
int tasksPerProducer = 10;
for (int i = 0; i < numProducer; i++) {
new Thread(new Producer(tasksPerProducer)).start();
}
int numConsumer = numProducer; // producers will put N EOFs to kill N consumers.
for (int i = 0; i < numConsumer; i++) {
new Thread(new Consumer()).start();
}
}
public static void main(String[] args) throws IOException {
Test4 t = new Test4();
t.runTest();
}
}
Instead of using two semaphores why dont you use a single semaphore to such that the synchronization is made between threads link
Additional you can use ArrayBlockingQueue which are thread safe to properly demonstrate the Producer Consumer Problem.

Queue unexpectedly puts last element in the front when I call poll()

I have the following code. I'm trying to do a breadth first search of a tree that I created call HabitItem.
Here is queue traveral
import java.io.File;
import java.util.*;
import java.util.concurrent.PriorityBlockingQueue;
public static void traverseQueue() {
queueHabitItems.add(head);
while(!queueHabitItems.isEmpty()){
HabitItem node = queueHabitItems.peek();
for(int i = 0; i < node.children.size(); i++)
{
HabitItem it = node.children.get(i);
System.out.print("node: ");
System.out.print(node.name);
System.out.print(", child: ");
System.out.println(it.name);
queueHabitItems.offer(it);
}
queueHabitItems.poll();
System.out.println("Something Good Is Coming");
}
}
I'm trying to implement a Queue. And I'm using the Poll() function to remove elements. Suppose I have the following Data in the Queue.
A B C D E
And I want to use poll() to remove the front element. Well for some reason, E goes to the front of the list, such that it becomes
E B C D
Am I doing something wrong or is there something that I don't fundamentally understand about Queues? Shouldn't B be the front item?
public class myMain {
static PriorityQueue<HabitItem> queueHabitItems = new PriorityQueue<HabitItem>();
static HabitItem head = new HabitItem("A");
static HabitItem B = new HabitItem("B");
static HabitItem C = new HabitItem("C");
static HabitItem D = new HabitItem("D");
static HabitItem E = new HabitItem("E");
static HabitItem F = new HabitItem("F");
static HabitItem G = new HabitItem("G");
static HabitItem H = new HabitItem("H");
static HabitItem I = new HabitItem("I");
static HabitItem J = new HabitItem("J");
static HabitItem K = new HabitItem("K");
static HabitItem L = new HabitItem("L");
static HabitItem M = new HabitItem("M");
static HabitItem N = new HabitItem("N");
static HabitItem O = new HabitItem("O");
public static void hardCodeHabits() {
System.out.print(D.id);
head.children.add(B);
head.children.add(C);
head.children.add(D);
head.children.add(E);
B.children.add(F);
B.children.add(G);
B.children.add(H);
C.children.add(I);
B.children.add(J);
E.children.add(K);
I.children.add(L);
L.children.add(N);
L.children.add(M);
N.children.add(O);
System.out.print(D.id);
}
public static void traverseQueue() {
queueHabitItems.add(head);
while(!queueHabitItems.isEmpty()){
HabitItem node = queueHabitItems.peek();
for(int i = 0; i < node.children.size(); i++)
{
HabitItem it = node.children.get(i);
System.out.print("node: ");
System.out.print(node.name);
System.out.print(", child: ");
System.out.println(it.name);
queueHabitItems.offer(it);
}
queueHabitItems.remove();
System.out.println("Something Good Is Coming");
}
}
public static void main(String[] args) {
System.out.println("Hello world");
hardCodeHabits();
traverseQueue();
try{
Scanner x = new Scanner(new File("justText.txt"));
Formatter y = new Formatter(new File("output.txt"));
y.format("%s", "hey");
y.close();
while (x.hasNext()) {
System.out.println(x.next());
}
}
catch(Exception e) {
System.out.println("Couldn't open the file!");
}
}
}
This is my HabitItems class
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
public class HabitItem implements Comparable<HabitItem> {
static int Counter = 0;
String name;
boolean completed[] = new boolean[7];
List<HabitItem> children = new ArrayList<HabitItem>();
int id;
public String getName(){
return name;
}
public boolean[] getCompleted(){
return completed;
}
public void setCompleted(int index, boolean checked){
completed[index] = checked;
}
public boolean isChecked(int index){
return completed[index];
}
public HabitItem(String name) {
super();
Counter++;
this.id = Counter;
this.name = name;
for(int i = 0; i < 7; i++){
completed[i] = false;
}
}
public HabitItem(int id) {
super();
Counter++;
this.id = id;
}
public int compareTo(HabitItem o) {
if(o.id == this.id)
{
return 1;
}
else
{
return 0;
}
}
}
Again, don't use peek, use remove:
while (!queueHabitItems.isEmpty()) {
//!! HabitItem node = queueHabitItems.peek();
HabitItem node = queueHabitItems.remove();
for (int i = 0; i < node.children.size(); i++) {
HabitItem it = node.children.get(i);
System.out.print("node: ");
System.out.print(node.name);
System.out.print(", child: ");
System.out.println(it.name);
queueHabitItems.offer(it);
}
// !! queueHabitItems.remove();
System.out.println("Something Good Is Coming");
}
The peek call just peeks into the collection but does not respect the priority. The poll and remove do respect this.
This is very old and probably doesn't matter anymore. But I will just say that it turned out that I was confused because I thought a priorityQueue was the exact same thing as a queue.

Java dining philosophers monitors

I have a problem in my Java code that should simulate dining pholosophers problem, which is described here: http://en.wikipedia.org/wiki/Dining_philosophers_problem
I want to output the current state of all philosophers every time one of them eats or thinks. Output should look something like this:
"O X O o X (2)", where "X" means that philosopher eats, "O" means that he is thinking, and "o" means that he is waiting for chopsticks. The number in brackets indicates the number of the philosopher whose state has changed. The problem that I have is that only philosophers 1 and 3 (sometimes 2 and 4) eat, while others always think or wait for forks, and that repeats constantly, so the output looks like this:
O X O O O (2)
o X o X O (4)
o O o X o (2)
o O o O o (4)
o X o O o (2)
o X o X o (4)
o O o X o (2)
...
Complete code is here:
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class Stick{
boolean available;
public Stick(){
available = true;
}
public void setAvailability(boolean flag){
this.available = flag;
}
public boolean getAvailability(){
return available;
}
}
class Philosopher extends Thread{
private int id;
private Stick l, r;
private Lock monitor;
private Condition[] cond;
private Problem p;
private void outputState(int _id){
StringBuffer sb = new StringBuffer();
for(int i=0; i<5; i++)
sb.append(p.getState(i) + " ");
System.out.println(sb + "(" + (_id+1) + ")");
}
private void takeChopSticks(int _id) throws InterruptedException{
monitor.lock();
try{
p.setState(_id, "o");
while(!l.getAvailability() || !r.getAvailability()){
cond[_id].await();
}
l.setAvailability(false);
r.setAvailability(false);
p.setState(_id, "X");
outputState(_id);
}finally{
monitor.unlock();
}
}
private void eat() throws InterruptedException{
Thread.sleep(1000);
}
private void think(int _id) throws InterruptedException{
Thread.sleep(2000);
}
public void run(){
while(true){
try{
takeChopSticks(this.id);
eat();
releaseChopSticks(this.id);
think(this.id);
}catch(InterruptedException e){System.out.println("srusila se metoda run()");}
}
}
private void releaseChopSticks(int _id) throws InterruptedException{
monitor.lock();
try{
l.setAvailability(true);
r.setAvailability(true);
cond[_id].signalAll();
cond[(_id+4)%5].signalAll();
p.setState(_id, "O");
outputState(_id);
}finally{
monitor.unlock();
}
}
public Philosopher(Problem _p, int _id, Stick _l, Stick _r, Lock m){
cond = new Condition[5];
monitor = m;
id = _id;
l = _l;
r = _r;
p = _p;
for(int i=0; i<5; i++)
cond[i] = monitor.newCondition();
}
}
public class Problem {
Thread[] t;
Stick[] s;
private enum State {O, X, o};
private State[] state;
public State getState(int id){
return state[id];
}
public void setState(int id, String s){
if(s == "o")
state[id] = State.o;
else if(s=="O")
state[id] = State.O;
else if(s=="X")
state[id] = State.X;
}
public Problem(){
state = new State[5];
t = new Thread[5];
s = new Stick[5];
for(int i=0; i<5; i++){
s[i] = new Stick();
state[i] = State.O;
}
Lock m = new ReentrantLock();
for(int i=0; i<5; i++)
t[i] = new Philosopher(this, i, s[i], s[(i+4)%5], m);
for(int i=0; i<5; i++)
t[i].start();
}
public static void main(String[] args){
new Problem();
}
}
I know there are allready several questions about dining philosophers in Java, but none of them seem to help, and my code is a bit different. Thanks.
I've modified it quite a bit and it finally works.
The code is:
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class Chopstick{
private boolean availability;
public Chopstick(){
availability = true;
}
public boolean getAvailability(){
return availability;
}
public void setAvailability(boolean flag){
availability = flag;
}
}
class Helper{
private Lock mutex = null;
private Condition[] cond;
private String[] state;
private int[] id;
private void outputState(int id){
StringBuffer line = new StringBuffer();
for(int i=0; i<5; i++)
line.append(state[i] + " ");
System.out.println(line + "(" + (id+1) + ")");
}
public Helper(){
id = new int[5];
mutex = new ReentrantLock();
state = new String[5];
cond = new Condition[5];
for(int i=0; i<5; i++){
id[i] = i;
state[i] = "O";
cond[i] = mutex.newCondition();
}
}
public void setState(int id, String s){
state[id] = s;
}
public void grabChopsticks(int id, Chopstick l, Chopstick r){
mutex.lock();
try{
setState(id, "o");
while(!l.getAvailability() || !r.getAvailability())
cond[id].await();
l.setAvailability(false);
r.setAvailability(false);
setState(id, "X");
outputState(id);
} catch (InterruptedException e) {
e.printStackTrace();
}finally{
mutex.unlock();
}
}
public void releaseChopsticks(int id, Chopstick l, Chopstick r){
mutex.lock();
try{
setState(id, "O");
l.setAvailability(true);
r.setAvailability(true);
cond[(id+1)%5].signalAll();
cond[(id+4)%5].signalAll();
outputState(id);
}finally{
mutex.unlock();
}
}
}
class Philosopher implements Runnable{
private Helper hlp;
private Chopstick l, r;
private int id;
public Philosopher(int id, Chopstick l, Chopstick r, Helper i){
this.hlp = i;
this.l = l;
this.r = r;
this.id = id;
}
private void eat(){
try{
Thread.sleep(2000);
}catch(InterruptedException e){}
}
private void think(){
try{
Thread.sleep(2000);
}catch(InterruptedException e){}
}
public void run(){
while(true){
hlp.grabChopsticks(id, l, r);
eat();
hlp.releaseChopsticks(id, l, r);
think();
}
}
}
public class Problem {
private Chopstick[] s;
private Philosopher[] f;
private Helper hlp;
private void init(){
s = new Chopstick[5];
f = new Philosopher[5];
hlp = new Helper();
for(int i=0; i<5; i++)
s[i] = new Chopstick();
for(int i=0; i<5; i++){
f[i] = new Philosopher(i, s[i], s[(i+4)%5], hlp);
new Thread(f[i]).start();
}
}
public Problem(){
init();
}
public static void main(String[] args){
new Problem();
}
}

Categories