I want to implement a solution for Readers-Writer problem. The main rule is, only one writer can write at a time and no other writer or reader can write or read, but if a writer doesn't write , multiple readers can read. In the main class, I tried to run threads with executorService.execute but i had some problems i guess. I don't know much about executorService. The program never ends and I guess there is some output problems.
My code is below:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
public class ReaderWriter {
public static void main(String [] args) {
ExecutorService executorService = Executors.newCachedThreadPool();
ReadWriteLock RW = new ReadWriteLock();
executorService.execute(new Writer(RW));
executorService.execute(new Writer(RW));
executorService.execute(new Writer(RW));
executorService.execute(new Writer(RW));
executorService.execute(new Reader(RW));
executorService.execute(new Reader(RW));
executorService.execute(new Reader(RW));
executorService.execute(new Reader(RW));
}
}
class ReadWriteLock{
static Semaphore readLock = new Semaphore(1);
static Semaphore writeLock = new Semaphore(1);
volatile static int readCount = 0;
public void readLock() throws InterruptedException {
readLock.acquire();
readCount++;
if (readCount == 1) {
writeLock.acquire();
}
readLock.release();
//Reading section
System.out.println("Thread "+Thread.currentThread().getName() + " is READING");
Thread.sleep(1500);
System.out.println("Thread "+Thread.currentThread().getName() + " has FINISHED READING");
//Releasing section
readLock.acquire();
readCount--;
if(readCount == 0) {
writeLock.release();
}
readLock.release();
}
public void writeLock() throws InterruptedException {
writeLock.acquire();
System.out.println("Thread "+Thread.currentThread().getName() + " is WRITING");
Thread.sleep(2500);
writeLock.release();
System.out.println("Thread "+Thread.currentThread().getName() + " has finished WRITING");
}
}
class Writer implements Runnable
{
private ReadWriteLock RW_lock;
public Writer(ReadWriteLock rw) {
RW_lock = rw;
}
public void run() {
while (true){
try {
RW_lock.writeLock();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Reader implements Runnable
{
private ReadWriteLock RW_lock;
public Reader(ReadWriteLock rw) {
RW_lock = rw;
}
public void run() {
while (true){
try {
RW_lock.readLock();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
And the output is not right i think for this problem:
Thread pool-1-thread-1 is WRITING
Thread pool-1-thread-2 is WRITING
Thread pool-1-thread-1 has finished WRITING
Thread pool-1-thread-2 has finished WRITING
Thread pool-1-thread-3 is WRITING
Thread pool-1-thread-3 has finished WRITING
Thread pool-1-thread-4 is WRITING
Thread pool-1-thread-4 has finished WRITING
Thread pool-1-thread-5 is READING
Thread pool-1-thread-8 is READING
Thread pool-1-thread-7 is READING
Thread pool-1-thread-6 is READING
Thread pool-1-thread-8 has FINISHED READING
Thread pool-1-thread-5 has FINISHED READING
Thread pool-1-thread-8 is READING
Thread pool-1-thread-5 is READING
Thread pool-1-thread-6 has FINISHED READING
Thread pool-1-thread-6 is READING
Thread pool-1-thread-7 has FINISHED READING
Thread pool-1-thread-7 is READING
Thread pool-1-thread-5 has FINISHED READING
Thread pool-1-thread-5 is READING
Thread pool-1-thread-8 has FINISHED READING
In this output there is 2 writers writing at the same time.
OUTPUT EDIT:
Thread pool-1-thread-1 is WRITING
Thread pool-1-thread-1 has finished WRITING
Thread pool-1-thread-1 is WRITING
Thread pool-1-thread-1 has finished WRITING
Thread pool-1-thread-4 is WRITING
Thread pool-1-thread-4 has finished WRITING
Thread pool-1-thread-3 is WRITING
Thread pool-1-thread-3 has finished WRITING
Thread pool-1-thread-2 is WRITING
Thread pool-1-thread-2 has finished WRITING
Thread pool-1-thread-8 is READING
Thread pool-1-thread-7 is READING
Thread pool-1-thread-5 is READING
Thread pool-1-thread-6 is READING
Thread pool-1-thread-8 has FINISHED READING
Thread pool-1-thread-7 has FINISHED READING
Thread pool-1-thread-5 has FINISHED READING
Thread pool-1-thread-6 has FINISHED READING
The program never ends and i guess there is some output problems.
Add a flag into the ReadWriteLock class to signals the Threads when they should stop working:
private final AtomicBoolean keep_working = new AtomicBoolean(true);
add a method in the ReadWriteLock class to signal the threads to stop:
public void stopThreads(){
keep_working.set(false);
}
and add the method to query the flag:
public boolean keepWorking(){
return keep_working.get();
}
adapt the Writer and Reader run methods, accordingly:
public void run() {
while (RW_lock.keepWorking()){
...
}
}
on the main class add a call to the methods ExecutorService.awaitTermination(), ReadWriteLock.stopThreads, and ExecutorService.shutdown():
public static void main(String [] args) {
ExecutorService executorService = Executors.newCachedThreadPool();
ReadWriteLock RW = new ReadWriteLock();
executorService.execute(new Writer(RW));
executorService.execute(new Writer(RW));
executorService.execute(new Writer(RW));
executorService.execute(new Writer(RW));
executorService.execute(new Reader(RW));
executorService.execute(new Reader(RW));
executorService.execute(new Reader(RW));
executorService.execute(new Reader(RW));
try {
executorService.awaitTermination(5, TimeUnit.SECONDS);
} catch (InterruptedException e) { // ...}
RW.stopThreads();
executorService.shutdown();
}
And the output is not right i think for this problem:
(...)
In this output there is 2 writers writing at the same time.
That is because in :
public void writeLock() throws InterruptedException {
writeLock.acquire();
System.out.println("Thread "+Thread.currentThread().getName() + " is WRITING");
Thread.sleep(2500);
writeLock.release();
System.out.println("Thread "+Thread.currentThread().getName() + " has finished WRITING");
}
you release the lock before printing "has finished WRITING" therefore, a thread waiting for that lock to be released enters and prints "is WRITING" before the first thread has time to print "has finished WRITING". So you need to change the code to:
public void writeLock() throws InterruptedException {
writeLock.acquire();
System.out.println("Thread "+Thread.currentThread().getName() + " is WRITING");
Thread.sleep(2500);
System.out.println("Thread "+Thread.currentThread().getName() + " has finished WRITING");
writeLock.release();
}
The main rule is, only one writer can write at a time and no other
writer or reader can write or read, but if a writer doesn't write ,
multiple readers can read.
Actually, you can take advantage of the Java ReadWriteLock Interface.
A ReadWriteLock maintains a pair of associated locks, one for
read-only operations and one for writing. The read lock may be held
simultaneously by multiple reader threads, so long as there are no
writers. The write lock is exclusive. All ReadWriteLock
implementations must guarantee that the memory synchronization effects
of writeLock operations (as specified in the Lock interface) also hold
with respect to the associated readLock. That is, a thread
successfully acquiring the read lock will see all updates made upon
previous release of the write lock.
A read-write lock allows for a greater level of concurrency in
accessing shared data than that permitted by a mutual exclusion lock.
It exploits the fact that while only a single thread at a time (a
writer thread) can modify the shared data, in many cases any number of
threads can concurrently read the data (hence reader threads). In
theory, the increase in concurrency permitted by the use of a
read-write lock will lead to performance improvements over the use of
a mutual exclusion lock. In practice this increase in concurrency will
only be fully realized on a multi-processor, and then only if the
access patterns for the shared data are suitable.
By using that interface you could simplify significantly the readLock and writeLock methods, to something as follows:
public void readLock() throws InterruptedException {
shared_resource.readLock().lock();
System.out.println("Thread "+Thread.currentThread().getName() + " is READING");
Thread.sleep(1500);
System.out.println("Thread "+Thread.currentThread().getName() + " has FINISHED READING");
shared_resource.readLock().unlock();
}
public void writeLock() throws InterruptedException {
shared_resource.writeLock().lock();
System.out.println("Thread "+Thread.currentThread().getName() + " is WRITING");
Thread.sleep(2500);
System.out.println("Thread "+Thread.currentThread().getName() + " has finished WRITING");
shared_resource.writeLock().unlock();
}
To complete, you should add a variable that counts the number of writes and reads. So that if there is nothing written, the read threads should wait, and in the meantime, the write thread should write something, and so.
You need to invoke the shutdown or shutdownAndAwaitTermination method of the ExecutorService in the main method.
Related
The thread pool executor is being executed in parallel to the main thread. The main thread is not waiting until the shutdown of the executor.
public static void main(String[] args) {
Date jobStartTime = null;
LOGGER.info("MainApp::Job started");
try {
MainApp obj = new MainApp();
// Getting the job Id of the job
String jobName=args[0]; //batch name
String fileName=args[1]; //sqoop file
LOGGER.info("MainApp::jobName: "+jobName+" fileName "+fileName);
currentJobID = obj.getMaxJobId(jobName);
LOGGER.info("MainApp:Job Id is" + currentJobID);
// Getting the start time of the job
jobStartTime = commonDB.getTime();
LOGGER.info("MainApp:Job Start time is" + jobStartTime);
JobDetails job=new JobDetails(currentJobID,jobName,fileName);
// Reading and parsing the sqoop file and executing the sqoop commands
CommandGenerator exec=new CommandGenerator();
List<TableInfo> commandList = exec.parseAndExec(job);
ThreadPoolExecutor tp = (ThreadPoolExecutor) Executors.newFixedThreadPool(10);
for (final TableInfo table : commandList) {
ParallelExecutor pe = new ParallelExecutor(table);
tp.execute(pe);
}
tp.shutdown();
while(!tp.isShutdown()){
}
job=new JobDetails(currentJobID,jobName,fileName,jobStartTime);
//put everything in one method
StatusAndMailUtils status=new StatusAndMailUtils();
status.onJobCompletion(job);
} catch (Exception e) {
// TODO Auto-generated catch block
LOGGER.info("MainApp::Exception");
e.printStackTrace();
}
}
I have used the while loop to keep the main thread waiting mean while the executor threads are in progress. But, it is not helping. Please let me know how to make the main thread wait.
while(!tp.isShutdown()){
}
After having called shutdown(), you can use awaitTermination(long timeout, TimeUnit unit) to block the calling thread until all tasks have completed execution.
As timeout you can use a value excessively big if you want to wait as long as it is needed for the tasks to complete however as it could make your thread wait forever if a task never ends, it is always better to set a reasonable timeout in order to execute some tasks if it is abnormally too long.
For example:
tp.shutdown();
tp.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);
Of course it's not waiting. That's the whole idea of creating a threadpool, so your main thread can perform other tasks while the threadpool is executing additional tasks.
You can use the awaitTermination(long timeout, TimeUnit unit) method to have your main thread pause while the threadpool finishes its tasks.
You can also submit these Runnables and wait them to complete. It is also possible to specify a timeout to wait for the threads to execute before throwing an exception.
List<Future<ParallelExecutor>> tasks = new ArrayList<>();
ExecutorService tp = Executors.newFixedThreadPool(10);
for (final TableInfo table : commandList) {
ParallelExecutor pe = new ParallelExecutor(table);
tasks.add(tp.submit(pe));
}
for (Future<ParallelExecutor > p : tasks) {
p.get(); // with timeout p.get(10, TimeUnit.SECONDS);
}
tp.shutdown();
I am trying to get lock on a thread using following piece of code:
Lock lock = readLock ? getLock(key).readLock() : getLock(key).writeLock();
try {
boolean locked = lock.tryLock(DEFAULT_TRY_TIME, DEFAULT_TRY_TIME_UNIT); //line 3
// If false, lock is not acquired
if (!locked) {
throw new TryLockTimeoutException(
key + ": Failed to acquire " + lock + " within " + DEFAULT_TRY_TIME_STRING);
}
}
Line 3 returns false after 30 minutes hence TryLockTimeoutException is thrown with error as:
com.concurrent.TryLockTimeoutException: keyIp : Failed to acquire java.util.concurrent.locks.ReentrantReadWriteLock$WriteLock#74be2cee[Unlocked] within 30MINUTES
at com.concurrent.NeAccessLockMap.acquireReadOrWriteLock(NeAccessLockMap.java:72)
Notice that lock state is shown as Unlocked in error.
I am not able to understand why would this happen? Why thread is not able to get lock even when the lock is free.
In your example you try to acquire a write lock, but the read lock is already locked, which prevents you from acquiring the write lock.
Because you can either have one or more read locks acquired, or a single write lock acquired, the write lock is marked as Unlocked when there are read locks acquired.
Try the following code:
ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
new Thread() {
#Override
public void run() {
readWriteLock.readLock().lock();
try {
// block the read lock
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
if (!readWriteLock.writeLock().tryLock(1, TimeUnit.SECONDS)) {
System.out.println(readWriteLock);
System.out.println(readWriteLock.readLock());
System.out.println(readWriteLock.writeLock());
}
would have output like:
java.util.concurrent.locks.ReentrantReadWriteLock#31221be2[Write locks = 0, Read locks = 1]
java.util.concurrent.locks.ReentrantReadWriteLock$ReadLock#377dca04[Read locks = 1]
java.util.concurrent.locks.ReentrantReadWriteLock$WriteLock#728938a9[Unlocked]
I have an application that is running jobs that require two threads for every job. The two threads normally do some work and finish shortly after each other. Then after the second thread finishes I need to do some cleanup but since the threads are doing some network IO, it is possible for one thread to get blocked for a long time. In that case, I want the cleanup to take place a few seconds after the first thread finishes.
I implemented this behaviour with the following piece of code in a callback class:
private boolean first = true;
public synchronized void done() throws InterruptedException {
if (first) {
first = false;
wait(3000);
// cleanup here, as soon as possible
}
else {
notify();
}
}
Both threads invoke the done() method when they finish. The first one will then block in the wait() for at most 3 seconds but will be notified immediately when the seconds thread invokes the done() method.
I have tested this implementation and it seems to work well but I'm am curious if there's a better way of doing this. Even though this implementation doesn't look too complicated, I'm afraid that my program will deadlock or have some unsuspected synchronization issue.
I hope I understood your need. You want to wait for thread-a to complete and then wait either 3 seconds or for the end of thread-b.
It is better to use the newer Concurrent tools instead of the old wait/notify as there are so many edge cases to them.
// Two threads running so count down from 2.
CountDownLatch wait = new CountDownLatch(2);
class TestRun implements Runnable {
private final long waitTime;
public TestRun(long waitTime) {
this.waitTime = waitTime;
}
#Override
public void run() {
try {
// Wait a few seconds.
Thread.sleep(waitTime);
// Finished! Count me down.
wait.countDown();
System.out.println(new Date() + ": " + Thread.currentThread().getName() + " - Finished");
} catch (InterruptedException ex) {
System.out.println(Thread.currentThread().getName() + " - Interrupted");
}
}
}
public void test() throws InterruptedException {
// ThreadA
Thread threadA = new Thread(new TestRun(10000), "Thread A");
// ThreadB
Thread threadB = new Thread(new TestRun(30000), "Thread B");
// Fire them up.
threadA.start();
threadB.start();
// Wait for all to finish but threadA must finish.
threadA.join();
// Wait up to 3 seconds for B.
wait.await(3, TimeUnit.SECONDS);
System.out.println(new Date() + ": Done");
threadB.join();
}
happily prints:
Tue Sep 15 16:59:37 BST 2015: Thread A - Finished
Tue Sep 15 16:59:40 BST 2015: Done
Tue Sep 15 16:59:57 BST 2015: Thread B - Finished
Added
With the new clarity - that the end of any thread starts the timer - we can use a third thread for the cleanup. Each thread must call a method when it finishes to trigger the cleanup mechanism.
// Two threads running so count down from 2.
CountDownLatch wait = new CountDownLatch(2);
class TestRun implements Runnable {
private final long waitTime;
public TestRun(long waitTime) {
this.waitTime = waitTime;
}
#Override
public void run() {
try {
// Wait a few seconds.
Thread.sleep(waitTime);
// Finished! Count me down.
wait.countDown();
System.out.println(new Date() + ": " + Thread.currentThread().getName() + " - Finished");
// Record that I've finished.
finished();
} catch (InterruptedException ex) {
System.out.println(Thread.currentThread().getName() + " - Interrupted");
}
}
}
Runnable cleanup = new Runnable() {
#Override
public void run() {
try {
// Wait up to 3 seconds for both threads to clear.
wait.await(3, TimeUnit.SECONDS);
// Do your cleanup stuff here.
// ...
System.out.println(new Date() + ": " + Thread.currentThread().getName() + " - Finished");
} catch (InterruptedException ex) {
System.out.println(Thread.currentThread().getName() + " - Interrupted");
}
}
};
final AtomicBoolean cleanupStarted = new AtomicBoolean(false);
private void finished() {
// Make sure I only start the cleanup once.
if (cleanupStarted.compareAndSet(false, true)) {
new Thread(cleanup, "Cleanup").start();
}
}
public void test() throws InterruptedException {
// ThreadA
Thread threadA = new Thread(new TestRun(10000), "Thread A");
// ThreadB
Thread threadB = new Thread(new TestRun(30000), "Thread B");
// Fire them up.
threadA.start();
threadB.start();
System.out.println(new Date() + ": Done");
}
As done method is synchronized, so only one thread can execute at a time, with this second will wait to send notify until first finishes its whole job, which might cause performance bottleneck.
I would rather design it with short synchronized block which would primarily update the boolean first.
This question already has answers here:
Parallel Computing In Java [closed]
(3 answers)
Closed 8 years ago.
I'm making a twitter analysis software with java and I want to create two threads that run in parallel: One is to stream the tweets using twitter streaming API and one is to analyze. I'm not sure of how to start .
Taken right from a java tutorial. Let me know if you have specific quesitons:
public class SimpleThreads {
// Display a message, preceded by
// the name of the current thread
static void threadMessage(String message) {
String threadName =
Thread.currentThread().getName();
System.out.format("%s: %s%n",
threadName,
message);
}
private static class MessageLoop
implements Runnable {
public void run() {
String importantInfo[] = {
"Mares eat oats",
"Does eat oats",
"Little lambs eat ivy",
"A kid will eat ivy too"
};
try {
for (int i = 0;
i < importantInfo.length;
i++) {
// Pause for 4 seconds
Thread.sleep(4000);
// Print a message
threadMessage(importantInfo[i]);
}
} catch (InterruptedException e) {
threadMessage("I wasn't done!");
}
}
}
public static void main(String args[])
throws InterruptedException {
// Delay, in milliseconds before
// we interrupt MessageLoop
// thread (default one hour).
long patience = 1000 * 60 * 60;
// If command line argument
// present, gives patience
// in seconds.
if (args.length > 0) {
try {
patience = Long.parseLong(args[0]) * 1000;
} catch (NumberFormatException e) {
System.err.println("Argument must be an integer.");
System.exit(1);
}
}
threadMessage("Starting MessageLoop thread");
long startTime = System.currentTimeMillis();
Thread t = new Thread(new MessageLoop());
t.start();
threadMessage("Waiting for MessageLoop thread to finish");
// loop until MessageLoop
// thread exits
while (t.isAlive()) {
threadMessage("Still waiting...");
// Wait maximum of 1 second
// for MessageLoop thread
// to finish.
t.join(1000);
if (((System.currentTimeMillis() - startTime) > patience)
&& t.isAlive()) {
threadMessage("Tired of waiting!");
t.interrupt();
// Shouldn't be long now
// -- wait indefinitely
t.join();
}
}
threadMessage("Finally!");
}
}
You can start by looking at java.lang.Thread and java.lang.Runnable.
The most basic way to create a thread is to extend Thread or override Runnable.
Simple, a thread is already a seperate process. So two threads are two seperate processes.
ie.
Thread streamThread = new Thread(new Runnable()); // You have to implement the run() method
streamThread.start();
Thread analyzeThread = new Thread(new Runnable()); // You have to implement the run() method
analyzeThread.start();
That's all there is to it.
I am trying to make several consumer threads that listen to one producer thread wait until the producer has something to publish. The code that I thought would work "loses" the lock on being put into and taken out of a shared class.
In a controller class I start the thread running with
Server server = new Server();
Thread serverThread = new Thread(server,"Server");
serverThread.start();
Consumer consumer = new Consumer();
Thread consumerThread;
for (int i =0;i<6;i++){
consumerThread = new Thread(consumer,"Consumer No:"+i);
consumerThread.start();
server.threadRefs[i]= consumerThread;
}
The consumer classes put details of threads into the Map as follows:
public class Consumer implements Runnable {
private ReentrantLock lock = new ReentrantLock();
private Condition cond = lock.newCondition();
#Override
public void run() {
long threadID = Thread.currentThread().getId();
while (true) {
try {
lock.lock();
MDRequest.threadLocks.put(threadID, lock);
System.out.println("Thread " + threadID + " lock = " + lock.toString());
cond.await();
System.out.println("Thread " + threadID + " done waiting");
} catch (InterruptedException ex) {
System.out.println("Interruped " + threadID);
} finally {
lock.unlock();
}
System.out.println("Finished " + threadID);
}
}
The shared class is simply:
public class MDRequest {
protected static ConcurrentHashMap<Long, ReentrantLock> threadLocks = new ConcurrentHashMap<Long, ReentrantLock>();
The Server has the following run() method:
public void run() {
try {
Thread.sleep(5000);
} catch (InterruptedException ex) {
Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
}
Set<Long> keys = MDRequest.threadLocks.keySet();
Long[] threadIDs = keys.toArray(new Long[1]);
// generates a random series of numbers for each thread and notifies threads about them
while (true) {
Random random = new Random();
int threadRef = random.nextInt(5);
System.out.println("About to signal thread " + threadIDs[threadRef].toString());
// notify the thread of the data
ReentrantLock lock = MDRequest.threadLocks.get(threadIDs[threadRef]);
System.out.println("Thread " + threadIDs[threadRef].toString() + " lock = " + lock.toString());
Condition cond = lock.newCondition();
cond.signal();
lock.unlock();
}
The output is as follows:
Thread 11 lock = java.util.concurrent.locks.ReentrantLock#272d7a10[Locked by thread Consumer No:0]
Thread 12 lock = java.util.concurrent.locks.ReentrantLock#272d7a10[Locked by thread Consumer No:1]
Thread 13 lock = java.util.concurrent.locks.ReentrantLock#272d7a10[Locked by thread Consumer No:2]
Thread 14 lock = java.util.concurrent.locks.ReentrantLock#272d7a10[Locked by thread Consumer No:3]
Thread 15 lock = java.util.concurrent.locks.ReentrantLock#272d7a10[Locked by thread Consumer No:4]
Thread 16 lock = java.util.concurrent.locks.ReentrantLock#272d7a10[Locked by thread Consumer No:5]
About to signal thread 14
Thread 14 lock = java.util.concurrent.locks.ReentrantLock#272d7a10[Unlocked]
Exception in thread "Price Server" java.lang.IllegalMonitorStateException
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.signal(AbstractQueuedSynchronizer.java:1885)
at faster.Server.run(Server.java:46)
at java.lang.Thread.run(Thread.java:695)
From the output int the Server class I can see that when I read the lock out of the Map it now has a status of "Unlocked". When it was put in it had a status of Locked on thread 14.
Why does the reference to the ReentrantLock "lose" the lock?
Is there a way of sharing the lock between the multiple consumer threads and the server thread in a way that the lock is not lost?
The problem you are facing is may be because of the following line in Server
Condition cond = lock.newCondition();
cond.signal();
lock.unlock();
Do you need to call unlock() from the Server for a Lock which is locked by the Consumer? I think calling signal() will suffice.
Think about this.
The problem is thread in Server class tries to unlock but has not lock the Lock
lock.unlock();
Please see ReentrantLock documentation where is clearly stated:
If the current thread is not the holder of this lock then IllegalMonitorStateException is thrown.