So lately i ve been trying to wrap my head around concurrency. And currently I m trying to find a solution for the ReaderWriter Problem.
I got a class File, it counts the number of Readers/Writers and has two Semaphores.
When a Reader tries to read it has to wait as long as there is a Writer Thread writing. When it enters readCount gets incremented within the readerSemaphore
& decremented within the same Semaphore when it leaves.
When a Writer tries to enter it has to wait for as long as there is more than one reader. When it enters it aquires the writerSemaphore and increaese the writerCount. When it leaves it releases the Semaphore.
For some reason that I cant figure out the Writers are not editing the String file in class File.
Thanks in advance :)
public class Main {
public static void main(String[]args) {
File file = new File("1. Chapter: ");
Writer w1 = new Writer(file, " w1 ");
Writer w2 = new Writer(file, " w2 ");
Reader r1 = new Reader(file);
Reader r2 = new Reader(file);
Reader r3 = new Reader(file);
Reader r4 = new Reader(file);
Reader r5 = new Reader(file);
w1.start();
w2.start();
r1.start();
r2.start();
r3.start();
r4.start();
r5.start();
try {
w2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("-> Final output: " + file.file);
}}
public class File {
public String file;
private int readCount;
private int writeCount;
private Semaphore semReader;
private Semaphore semWriter;
public File(String file) {
this.file = file;
readCount = 0;
writeCount = 0;
semReader = new Semaphore(1);
semWriter = new Semaphore(1);
}
public synchronized void startReading() {
try {
while(writeCount == 1) {
Thread.currentThread().wait();
}
semReader.acquire();
readCount++;
semReader.release();
System.out.println(" --- File was read");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized String endReading() {
String temp = file;
try {
semReader.acquire();
readCount--;
semReader.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
return temp;
}
public synchronized void startWriting(String edit) {
try {
while(readCount > 0) {
Thread.currentThread().wait();
}
semWriter.acquire();
writeCount++;
System.out.println(" --- File got edited");
file = file + "hi";
}
catch (Exception e) {
}
}
public synchronized void endWriting() {
writeCount--;
semWriter.release();
}}
public class Writer extends Thread {
private File file;
private String edit;
public Writer(File file, String edit) {
this.file = file;
this.edit = edit;
}
#Override
public void run() {
Random rand = new Random();
try {
sleep(1000);
System.out.println(">W: " + Thread.currentThread().getName() + " started first write.");
file.startWriting(" first" + edit);
sleep(3000);
System.out.println(">W: " + Thread.currentThread().getName() + " ended first write.");
file.endWriting();
sleep(2000);
System.out.println(">W: " + Thread.currentThread().getName() + " started second write.");
file.startWriting(" second" + edit);
sleep(3000);
System.out.println(">W: " + Thread.currentThread().getName() + " ended second write.");
file.endWriting();
System.out.println(">W: " + Thread.currentThread().getName() + " finished");
} catch (InterruptedException e) {
e.printStackTrace();
}
}}
public class Reader extends Thread {
private File file;
public Reader(File file) {
this.file = file;
}
#Override
public void run() {
Random rand = new Random();
try {
sleep(rand.nextInt(2000));
System.out.println(">R: " + Thread.currentThread().getName() + " startet first read.");
file.startReading();
sleep(3000);
System.out.print(">R: " + Thread.currentThread().getName() + " ended first read: ");
System.out.println(file.endReading());
sleep(rand.nextInt(2000));
System.out.println(">R: " + Thread.currentThread().getName() + " startet second read.");
file.startReading();
sleep(3000);
System.out.print(">R: " + Thread.currentThread().getName() + " ended second read: ");
System.out.println(file.endReading());
System.out.println(">R: " + Thread.currentThread().getName() + " finished");
} catch (InterruptedException e) {
e.printStackTrace();
}
}}
Edit:
Thread.currentThread().wait() was wrong.
Waiting on threads is discouraged in the java docs.
Thanks, #JB Nizet for helping me.
Related
I am trying to figure out the passengers' disembark and embark methods in my project. The problem is the passengers' count will not be in order and I couldn't figure out which flights are ongoing those disembark and embarking actions.
Objective: To figure out the way to add the flight number for passengers.
package airport_ccp;
import java.util.Random;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class airport_CCP {
public static void main(String[] args) {
Random rand = new Random();
Passengers passsenger = new Passengers();
//runway only got one, two gates
//runway is exclusive event, remain inclusive event for gates only
//gates available: 2, so create blockingqueue<runway>(2)
BlockingQueue<Gate> gates = new ArrayBlockingQueue<Gate>(2);
//threadpool for aircraft, two gates available
//so create a fixed threadpool for gates with 2 maximum
ExecutorService threadpool = Executors.newFixedThreadPool(2);
// 2 active inbound for 2 gates.
for (int i = 1; i <= 2; i++) {
gates.add(new Gate(i));
}
//10 flights
for(int i = 1; i <= 10; i++) {
try {
// 3 secnonds hold for new aircraft
Thread.sleep(rand.nextInt(3000));
threadpool.submit(new Aircraft(i, "land", gates));
//initial thought of input
ExecutorService executor = Executors.newCachedThreadPool();
for(int j=0; j<50; j++){
executor.submit(new Runnable() {
public void run() {
Passengers.getInstance().run();
}
});
}
executor.shutdown();
//input ends
} catch (InterruptedException e) {
e.printStackTrace();
}
}
threadpool.shutdown();
try {
if (threadpool.awaitTermination(100, TimeUnit.SECONDS)) {
for (int i = 1; i <= 2; i++) {
gates.take().printReport();
}
}
} catch (InterruptedException e) {
}
}
}
Below is my passenger class
package airport_ccp;
import java.util.Random;
import java.util.concurrent.Semaphore;
public class Passengers {
private static Passengers instance = new Passengers();
private Semaphore sema = new Semaphore(50, true); //set max to 50
private int passengercount = 0;
private Passengers() {
}
public static Passengers getInstance(){
return instance;
}
public void run() {
try {
sema.acquire();
System.out.println( "MH " /*ID input*/ + " : Passengers " + passengercount + " Disembarking");
} catch (InterruptedException ex) {
ex.printStackTrace();
}
try {
dorun();
}
finally {
System.out.println( "MH " /*ID input*/ + " : Passengers " + passengercount + " Embarking");
sema.release();
}
}
public void dorun() {
synchronized (this) {
passengercount++;
}
try {
Thread.sleep(2000);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
synchronized (this) {
passengercount--;
}
}
}
Aircraft class if there's any concern
package airport_ccp;
import java.util.Date;
import java.util.Random;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
public class Aircraft implements Runnable{
String status;
int ID;
Date arrival;
BlockingQueue<Gate> gatescount = null;
Gate gate;
public Aircraft(int ID, String status, BlockingQueue<Gate> gatescount) {
this.ID = ID;
this.gatescount = gatescount;
System.out.println("\t Time : " + java.time.LocalDateTime.now() + "\t" + " MH " + ID + " is calling for landing.");
}
#Override
public void run() {
try {
this.status = "land";
gate = gatescount.take();
System.out.println("\t MH " + ID + " has been assigned to " + gate.getName() + ".");
System.out.println( "\t Time : " + java.time.LocalDateTime.now() + "\t" + " MH " + ID + " is " + status + ".");
//Thread.sleep(1000*(1+new Random().nextInt(10)));
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
gate.inc(status);
this.status="depart";
System.out.println("\t Time : " + java.time.LocalDateTime.now() + "\t" + "MH " + ID + " has " + status);
gatescount.add(gate);
}
Err - why do you not pass in the flight number into the run method?
// in Passengers
public void run(int id) {
try {
sema.acquire();
System.out.println( "MH " + id + " : Passengers " + passengercount + " Disembarking");
} catch (InterruptedException ex) {
ex.printStackTrace();
}
try {
dorun();
}
finally {
System.out.println( "MH " + id + " : Passengers " + passengercount + " Embarking");
sema.release();
}
}
// when calling Passengers: pass in that ID
for(int i = 1; i <= 10; i++) {
try {
/* ... */
for(int j=0; j<50; j++){
int id = i; // <-- copy to a constant value; once assigned, id is never changed
executor.submit(new Runnable() {
public void run() {
Passengers.getInstance().run(id);
}
});
}
/* ... */
Note that the previous version used this code, which produces an error because the value of i changes in each iteration, while Java needs to ensure that it stays constant; using a reference that does not change (as above) solves the problem:
for(int j=0; j<50; j++){
executor.submit(new Runnable() {
public void run() {
Passengers.getInstance().run(i); // <-- fails, because i is not, and cannot be made, final
}
});
}
This will compile correctly however it says there is nothing to run in two different IDE. What seems to be the issue here. I have added lines to just print hi to troubleshoot but still nothing.
import java.util.concurrent.*;
//Creates class
public class project42 {
static class ExThread extends Thread {
//Variables are set
Semaphore sema;
String theName;
//
public ExThread(Semaphore sema, String theName) {
super(theName);
this.sema = sema;
this.theName = theName;
}
public void run() {
//test For Westbound
if (this.getName().equals("Westbound Cars")) {
try {
System.out.println(theName + " are waiting");
sema.acquire();
System.out.println(theName + " are attempting");
for (int i = 1; i < 6; i++) {
System.out.println("Westbound: " + i + " is waiting");
Thread.sleep(1000);
System.out.println("Westbound: " + i + " has crossed");
Thread.sleep(1000);
}
} catch (InterruptedException exc) {
System.out.println(exc);
}
System.out.println(theName + " has crossed the bridge");
sema.release();
} else {
//Test for eastbound
System.out.println(theName + " are waiting");
try {
System.out.println(theName + " are waiting");
sema.acquire();
System.out.println(theName + " are attempting");
for (int i = 1; i < 6; i++) {
System.out.println("Eastbound " + i + "is crossing");
Thread.sleep(1000);
System.out.println("Eastboud " + i + " is crossed");
Thread.sleep(1000);
}
} catch (InterruptedException exc) {
System.out.println(exc);
}
System.out.println(theName + " have crossed the bridge");
sema.release();
}
}
//main class
public static void main(String[] args) throws InterruptedException {
System.out.print("hi");
Semaphore sema = new Semaphore(1);
//creates cars
ExThread et1 = new ExThread(sema, "Westbound Cars");
ExThread et2 = new ExThread(sema, "WEastbound Cars");
//runs program
et1.start();
et2.start();
et1.join();
et1.join();
}
}
}
There is nothing to run, since your main is in the inner class (ExThread). It needs to be in the outer class (project42).
I have this current implementation but I couldn't append the new data that were being passed on in processName, activity and numberOfRecords. It just keeps creating a separate .txt file for each transaction.
#Override
public void saveSummaryLogs(String processName, String activity,
int numberOfRecords) throws Exception {
log.info("Test if this method is being executed.");
log.info(INSERT_LOGS_TO_FILE);
log.info("Creating a folder directory is being executed!");
try {
File f = new File(summaryLogsDbDir);
f.mkdirs();
} catch (Exception e) {
throw new Exception("Permission denied to create parent folder.",
e);
}
writeToFile(processName, activity, numberOfRecords);
log.info("writeToFile has been called and executed!");
}
public void writeToFile(String processName, String activity,
int numberOfRecords) throws Exception {
log.info("writeToFile is being executed!");
Date date = new Date();
SimpleDateFormat dateFormat = new SimpleDateFormat("ddMMyyy_HHmmss");
try (BufferedWriter out = new BufferedWriter(new FileWriter(
summaryLogsDbDir + LOGS_FILENAME + dateFormat.format(date)
+ ".txt"))) {
out.append(dateFormat.format(date)+ ": " + processName + "\n");
out.append(dateFormat.format(date)+ ": " + activity + "\n");
out.append(dateFormat.format(date)+ ": " + numberOfRecords + "\n");
} catch (Exception e) {
throw new Exception("Failed a summary-logs.txt file.", e);
}
log.info("writeToFile has been executed!");
}
Any help of advise is greatly appreciated. Thanks!
Im trying to make a simulation program in which:
A can is passed on to a conveyor
the can is filled
the can is checked
if the can is damaged, it will be removed from the conveyor
errors:
Exception in thread "RealtimeThread[pri=20,aperiodic]"
java.lang.NullPointerException
at assignment$Sensor.run(assignment.java:99)
at javax.realtime.RealtimeThread$Logic.run(RealtimeThread.java:244)
at javax.realtime.MemoryArea.enter(MemoryArea.java)
at javax.realtime.MemoryArea.enterInternal(MemoryArea.java:1472)
at javax.realtime.RealtimeThread$Logic.run(RealtimeThread.java:230)
I want to use the AsyncEventHandler to trigger a code if the can is damaged but it gives a NullPointerException error if the can is found damaged on the first try however the code works fine if the can is not damaged on the first loop.
import java.util.Random;
import javax.realtime.*;
public class realtime{
AsyncEvent damage;
public static void main(String[] args) {
realtime a = new realtime();
}
public realtime() {
Can can = new Can(1);
Conveyer conveyer = new Conveyer(can);
Sensor Sensor = new Sensor(can);
Grabber grabber = new Grabber(can, Sensor);
ReleaseParameters relConveyer = new PeriodicParameters(new RelativeTime(1000,0));
ReleaseParameters relSensor = new PeriodicParameters(new RelativeTime(1000,0));
conveyer.setReleaseParameters(relConveyer);
Sensor.setReleaseParameters(relSensor);
conveyer.start();
Sensor.start();
damage = new AsyncEvent();
damage.setHandler(grabber);
}
class Can {
int id;
boolean filled;
boolean damaged;
public Can(int id) {
this.id = id;
}
public void isFilled(boolean status) {
this.filled = status; //Print if the Can is filled
}
public void isDamaged(boolean status) {
this.damaged = status;
}
}
class Conveyer extends RealtimeThread {
Can can;
Random random = new Random();
public Conveyer(Can can) {
this.can = can;
}
#Override
public void run() { //While loop can be used to repeat
while(true) {
System.out.println("Can " + can.id + " has entered the conveyer");
System.out.println("Can " + can.id + " is being filled");
can.isFilled(true); //Sleep to give time to fill
System.out.println("Can " + can.id + " is filled");
System.out.println("Can " + can.id + " is being scanned");
can.isDamaged(random.nextBoolean());
try {
waitForNextRelease();
}
catch (Exception e) {}
}
}
}
class Sensor extends RealtimeThread{
Can can;
public Sensor(Can can) {
this.can = can;
}
#Override
public void run() { //While loop can be used to repeat
while(true) {
if(can.damaged) {
System.out.println("Can " + can.id + " is Damaged!");
damage.fire();
} else {
System.out.println("Can " + can.id + " is moved to Stage 2");
}
try {
waitForNextRelease();
}
catch (Exception e) {}
}
}
}
class Grabber extends AsyncEventHandler {
Can can;
RealtimeThread rtt;
boolean damaged = false;
public Grabber(Can can, RealtimeThread rtt) {
this.can = can;
this.rtt = rtt;
}
public void handleAsyncEvent() {
System.out.println("Can " + can.id + " is disposed");
}
}
}
You do not have a default constructor for your Can class. So in your Conveyor class you have Can can; This probably gives you the NullPointerException. Just add another constructor to your Can class like so:
public Can() {};
My producer-consumer problem runs perfectly for 1 producer and 1 consumer. It fails to run for 2 producer and 2 consumer. It is reaching some unknown deadlock state. I'm not able to debug. Can anyone please help me with it?
Constraint: One Producer has to produce upto 64 items. And consumer runs until it clears all produced items.
import java.util.Random;
import java.util.Scanner;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
class Producer implements Runnable {
private static int count = 1;
private Random rg = new Random();
private BlockingQueue<Object> queue = null;
private static int pc = 0;
static int maxPc = 0;
public Producer(BlockingQueue<Object> queue) {
this.queue = queue;
}
#Override
public void run() {
synchronized (queue) {
while(pc <= maxPc) {
try {
produce(pc++);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public void produce(int pc) throws InterruptedException {
synchronized(queue) {
while(queue.size() == 8) {
System.out.println(Thread.currentThread().getName() + " : Buffer full: waiting for consumer");
queue.wait();
}
}
synchronized(queue) {
System.out.println("Producer: " + Thread.currentThread().getName() + " adding item "+ pc + " to the queue");
queue.add(pc);
//Thread.sleep(1);
queue.notifyAll();
}
}
}
class Consumer implements Runnable {
private static int consumeCount = 0;
private BlockingQueue<Object> queue = null;
private Random rg = new Random();
public Consumer(BlockingQueue<Object> queue) {
this.queue = queue;
}
#Override
public void run() {
while(true) {
try {
consume();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public void consume() throws InterruptedException {
synchronized(queue) {
while(queue.isEmpty()) {
System.out.println(Thread.currentThread().getName() + ": Buffer empty: waiting for producer");
queue.wait();
}
}
synchronized(queue) {
//Thread.sleep(1);
System.out.println("Consumer: "+ Thread.currentThread().getName()+" removing item " + queue.take() + " from the queue");
consumeCount++;
queue.notifyAll();
if(consumeCount == ParallelProcess.maxCC + 1)
System.exit(0);
}
}
}
public class ParallelProcess {
static int maxCC = 0;
int numProducer;
int numConsumer;
private Thread[] cThreads;
private Thread[] pThreads;
private BlockingQueue<Object> queue = null;
public ParallelProcess(int numProducer, int numConsumer, int queueSize) {
this.numProducer = numProducer;
this.numConsumer = numConsumer;
this.queue = new ArrayBlockingQueue<Object>(queueSize);
// create consumer thread objects
cThreads = new Thread[numConsumer];
for (int i = 0; i < numConsumer; i++) {
cThreads[i] = new Thread(new Consumer(queue));
}
// create producer thread objects
pThreads = new Thread[numProducer];
for (int i = 0; i < numProducer; i++) {
pThreads[i] = new Thread(new Producer(queue));
}
}
public void execute() {
// start consumer threads
for (Thread t : cThreads) {
t.start();
}
// start producer threads
for (Thread t : pThreads) {
//System.out.println("tc");
t.start();
}
}
public static void main(String[] args) {
// provide number of producers, number of consumers and the
// max-queue-length
Scanner sc = new Scanner(System.in);
System.out.println("Enter no. of producer and conumer");
int n = sc.nextInt();
ParallelProcess process = new ParallelProcess(n, n, 8);
maxCC = n*64;
Producer.maxPc = maxCC;
process.execute();
// (new Thread()).start();
System.out.println("Thread: " + Thread.currentThread().getName() + " `enter code here`FINISHED");
}
}
First, you should merge synchronized block of the wait and queue.add(pc) to make it automatic, otherwise it might cause some inconstency.
Secondly, you should call queue.notify before wait, otherwise both producer and consumer might be blocked in wait state.
produce method:
public void produce(int pc) throws InterruptedException {
synchronized(queue) {
while(queue.size() == 8) {
System.out.println(Thread.currentThread().getName() + " : Buffer full: waiting for consumer");
queue.notifyAll();
queue.wait();
}
System.out.println("Producer: " + Thread.currentThread().getName() + " adding item "+ pc + " to the queue");
queue.add(pc);
//Thread.sleep(1);
queue.notifyAll();
}
}
consume method:
public void consume() throws InterruptedException {
synchronized(queue) {
while(queue.isEmpty()) {
System.out.println(Thread.currentThread().getName() + ": Buffer empty: waiting for producer");
queue.notifyAll();
queue.wait();
}
System.out.println("Consumer: "+ Thread.currentThread().getName()+" removing item " + queue.take() + " from the queue");
consumeCount++;
if(consumeCount == ParallelProcess.maxCC + 1)
System.exit(0);
}
}