This question already has answers here:
If I synchronized two methods on the same class, can they run simultaneously?
(12 answers)
Closed 5 years ago.
I have created a simple Worker :
public class Worker {
public synchronized void writeData() {
try {
System.out.println("write Data , thread id = " + Thread.currentThread().getId());
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized void readData() {
try {
System.out.println("readData , thread id = " + Thread.currentThread().getId());
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
AFAIK, If multiple thread access the same Worker instance, the synchronized only blocks threads that access the same method. AKA if thread A invokes writeData and B uses readData, they will not influence each other (Correct me if I am wrong).
BUT, when I tried to demo it by the code below:
private static void testWithThreads() {
final Worker worker = new Worker();
new Thread(() -> {
System.out.println("start read thread");
for (int i = 0; i < 20; i++) {
worker.readData();
}
}).start();
new Thread(() -> {
System.out.println("start write thread");
for (int i = 0; i < 20; i++) {
worker.writeData();
}
}).start();
}
I got the output like this (Note that we have Thread.sleep for 2 seconds here):
start read thread
readData , thread id = 10
start write thread
readData , thread id = 10
readData , thread id = 10
readData , thread id = 10
readData , thread id = 10
readData , thread id = 10
readData , thread id = 10
readData , thread id = 10
readData , thread id = 10
readData , thread id = 10
readData , thread id = 10
write Data , thread id = 11
write Data , thread id = 11
write Data , thread id = 11
write Data , thread id = 11
write Data , thread id = 11
write Data , thread id = 11
write Data , thread id = 11
write Data , thread id = 11
write Data , thread id = 11
write Data , thread id = 11
write Data , thread id = 11
write Data , thread id = 11
write Data , thread id = 11
write Data , thread id = 11
write Data , thread id = 11
write Data , thread id = 11
write Data , thread id = 11
write Data , thread id = 11
write Data , thread id = 11
write Data , thread id = 11
readData , thread id = 10
readData , thread id = 10
readData , thread id = 10
readData , thread id = 10
readData , thread id = 10
readData , thread id = 10
readData , thread id = 10
readData , thread id = 10
readData , thread id = 10
Can anyone explain this to me? It seems they blocked each other in some way.
the synchronized only blocks threads that access the same method
Wrong. It blocks threads trying to synchronize on the same object.
How it works is if A is using writeData for a Worker instance then B cannot use readData or writeData from the same Worker until it is given a chance.
If you were hoping to have your output to be:
read
write
read
write
etc...
then I would suggest using the functions wait(); and notifyAll();
This way you can make thread A give Thread B a turn once it is finished and vice versa.
You can read more about wait() and notifyAll()
here.
synchronized on a method level synchronizes access to all synchronized methods of the Object the methods belongs to, that only one thread can execute in any synchronized method of that object. The other threads will wait even if they try to access other synchronized method than the first thread.
The other Threads will block till the first one will get out from the synchronized blocks.
In your code beetween the invocation of synchornized methods in for loops, there is tiny time slot in which other thread can get into the writeData() before the first get again into readData() - a typical for loop is not atomic operation - but this time slot is so tiny, that it rarely happens - so your output looks like they are blocking each other in some way - and in one point the wind changes and other thread takes the lead.
to be more specific, comments are pointing where "unsynchronized" time slot begins in each for loop:
private static void testWithThreads() {
final Worker worker = new Worker();
new Thread(() -> {
System.out.println("start read thread");
for (int i = 0; i < 20; i++) {
worker.readData();
// any thread can now invoke writeData() if current thread is before next invocation of worker.readData();
}
try {
Thread.currentThread().join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
new Thread(() -> {
System.out.println("start write thread");
for (int i = 0; i < 20; i++) {
worker.writeData();
// any thread can now invoke readData() if current thread is before next invocation of worker.writeData();
}
try {
Thread.currentThread().join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
If you want to have better interleaving you can do one of these things:
use wait() and notify()
do not use synchronization on that methods - synchronize the
data.
move the sleep operation outside the synchronized write and read methods,
they will give the threads more chance to get into the
synchronized block.
Related
I wrote a small peice of program to demonstrate the usage of CountDownLatch class in java.
But, it not working as expected. I created 5 threads and assigned task to each thread. Now, each thread would wait for the start signal. Once the start signal is on, all thread start its work and call countDown(). Now, my main thread wait for all the thread to finish its work till it receives the done signal. But the output is not expected. Please help if I am missing anything in the concept.
Below is the program.
class Task implements Runnable{
private CountDownLatch startSignal;
private CountDownLatch doneSignal;
private int id;
Task(int id, CountDownLatch startSignal, CountDownLatch doneSignal){
this.startSignal = startSignal;
this.doneSignal = doneSignal;
this.id = id;
}
#Override
public void run() {
try {
startSignal.await();
performTask();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void performTask() {
try {
System.out.println("Task started by thread : " + id);
Thread.sleep(5000);
doneSignal.countDown();
System.out.println("Task ended by thread : " + id);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class CountDownLatchExample {
public static void main(String[] args) {
CountDownLatch startSignal = new CountDownLatch(1);
CountDownLatch doneSignal = new CountDownLatch(5);
for(int i=0; i < 5; ++i) {
new Thread(new Task(i, startSignal, doneSignal)).start();
}
System.out.println("Press enter to start work");
new Scanner(System.in).nextLine();
startSignal.countDown();
try {
doneSignal.await();
System.out.println("All Tasks Completed");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Output
Press enter to start work
Task started by thread : 0
Task started by thread : 4
Task started by thread : 3
Task started by thread : 2
Task started by thread : 1
Task ended by thread : 4
Task ended by thread : 2
Task ended by thread : 1
All Tasks Completed
Task ended by thread : 0
Task ended by thread : 3
Expected output
Press enter to start work
Task started by thread : 0
Task started by thread : 4
Task started by thread : 3
Task started by thread : 2
Task started by thread : 1
Task ended by thread : 4
Task ended by thread : 2
Task ended by thread : 1
Task ended by thread : 0
Task ended by thread : 3
All Tasks Completed
In your Task class, you have:
doneSignal.countDown();
System.out.println("Task ended by thread : " + id);
In other words, you count down the latch before you print "task ended". That allows the main thread to wake up from its call to doneSignal.await() and print "All Tasks Completed" before all the "task ended" print statements complete. Though note the "wrong output" will not always happen; sometimes you'll get your expected output.
Simply switch those two lines of code around to guarantee the output you want:
System.out.println("Task ended by thread : " + id);
doneSignal.countDown();
This ensures the print statement happens-before the doneSignal.countDown() call, which itself happens-before the main thread returns from doneSignal.await(). Thus, now the above "task ended" print statement happens-before the main thread wakes up and prints the "All Tasks Completed" message.
I want to run many GET and POST. In this example I use GET and for every task the same URL, but later it will be always a different URL for each task.
What I find that the time increases as the number of task and threads used.
num = 1 -> Done in 1846
num = 10 -> Done in 2114
num = 100 -> Done in 7204
num = 200 -> Done in 13720
If I have just 1 task I use 1 thread. If 10 tasks I use 10 threads, and so on.
I don't understand the time increase. If time for 1 task executed with 1 thread would take approx. 1 second, then for 10 tasks executed with 10 threads I would expect about the same time of 1 sec. Because on my 4-core CPU I can executed many threads concurrently.
Is it possibly that because I have only 1 network device, the requests don't get send in parallel but somehow in sequence?
// Amount of task and threads
int num = 10;
// Create many instances of the task
List<MyCallable> tasks = new ArrayList<>();
// Create num instances of MyCallable
ExecutorService executor = Executors.newFixedThreadPool(num);
List<Future<Void>> invokeAll = null;
long started = System.currentTimeMillis();
try {
invokeAll = executor.invokeAll(tasks);
} catch (InterruptedException ex) {
}
long ended = System.currentTimeMillis();
System.out.println("Done in " + (ended - started));
executor.shutdown();
private class MyCallable implements Callable<Void> {
public MyCallable() {}
#Override
public Void call() throws Exception {
int statusCode = sendGet();
return null;
}
private int sendGet() throws Exception {
CloseableHttpClient closeableHttpClient = HttpClients.createDefault();
CloseableHttpResponse closeableHttpResponse = closeableHttpClient.execute(new HttpGet("https://bing.com")); // https://www.google.com
int statusCode = closeableHttpResponse.getStatusLine().getStatusCode();
closeableHttpClient.close();
return statusCode;
}
}
I have my function executed this way:
#EventListener(classes = {ApplicationReadyEvent.class})
public void executeSendingNotificationToServer() {
serverNotificationService.trySendNotification(msgCount, msgTime)
.delaySubscription(Duration.ofMillis(notificationServerProperties.getExecutorDelay()))
.repeat()
.subscribeOn(Schedulers.single())
.subscribe();
}
method trySendNotification is executed somehow(it doesn't matter).
Why its not executed in single thread? I explicitly set Schedulers.single()
And the documentation states that it would be executed in one thread.
Instead I can observe that multiple threads are created(I put thread names logging in method and it prints different names)
You should move the subscribeOn before the delay.
Here is an example, using your code but printing the thread number:
Mono.fromCallable(() -> {
System.out.println("Thread = " + Thread.currentThread().getId());
return "hello world";
})
.delaySubscription(Duration.ofMillis(500))
.repeat()
.subscribeOn(Schedulers.single())
.subscribe();
The output, as you said, shows that it is executed in different threads:
Thread = 14
Thread = 15
Thread = 16
Thread = 17
Thread = 18
Thread = 19
Thread = 20
Thread = 21
Thread = 14
Now, if I move it before like this:
Mono.fromCallable(() -> {
System.out.println("Thread = " + Thread.currentThread().getId());
return "hello world";
})
.subscribeOn(Schedulers.single()) // <- BEFORE
.delaySubscription(Duration.ofMillis(500))
.repeat()
.subscribe();
The output becomes:
Thread = 14
Thread = 14
Thread = 14
Thread = 14
Thread = 14
Thread = 14
Thread = 14
Thread = 14
Thread = 14
I have a task where while generating a random password for user the SMS should go after 4 MIN, but the welcome SMS should go immediately. Since password I am setting first and need to send after 4 MIN I am making that thread sleep (Cant use ExecutorServices), and welcome SMS thread start.
Here is the code:
String PasswordSMS="Dear User, Your password is "+'"'+"goody"+'"'+" Your FREE
recharge service is LIVE now!";
String welcomeSMS="Dear goody, Welcome to XYZ";
try {
Thread q=new Thread(new GupShupSMSUtill(PasswordSMS,MOB_NUM));
Thread.sleep(4 * 60 * 1000);
q.start();
GupShupSMSUtill sendWelcomesms2=new GupShupSMSUtill(welcomeSMS, MOB_NUM);
Thread Bal3=new Thread(sendWelcomesms2);
Bal3.start();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
</code>
So if I change the order the thread sendWelcomesms2 Immediately starts.I have to send welcome SMS then password sms (After 4 Min) how its achievable ??
NOTE: Both SMS come after 4 MIN
Thread.sleep(4 * 60 * 1000);
delays execution of your currently running thread, your q.start() is not executed until the wait time is over. This order doesn't make sense.
Your thread is only created when
Thread q=new Thread(new GupShupSMSUtill(PasswordSMS,MOB_NUM));
is executed. Your thread is started when
q.start();
is executed. So if you want to achieve running the q thread while the main thread sleep, you should write your lines in this order:
Thread q=new Thread(new GupShupSMSUtill(PasswordSMS,MOB_NUM)); // Create thread
q.start(); // start thread
Thread.sleep(4 * 60 * 1000); // suspend main thread for 4 sec
You can use join():
String PasswordSMS = "Dear User, Your password is " + "\"" + "goody" + "\"" + " Your FREE recharge service is LIVE now!";
String welcomeSMS = "Dear goody, Welcome to XYZ";
try
{
GupShupSMSUtill sendWelcomesms2 = new GupShupSMSUtill(welcomeSMS, MOB_NUM);
Thread Bal3 = new Thread(sendWelcomesms2);
Bal3.start();
Thread q = new Thread(new GupShupSMSUtill(PasswordSMS, MOB_NUM));
q.start();
q.join();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
Or latch:
private static java.util.concurrent.CountDownLatch latch = new java.util.concurrent.CountDownLatch(1);
And the code:
String PasswordSMS = "Dear User, Your password is " + "\"" + "goody" + "\"" + " Your FREE recharge service is LIVE now!";
String welcomeSMS = "Dear goody, Welcome to XYZ";
try
{
GupShupSMSUtill sendWelcomesms2 = new GupShupSMSUtill(welcomeSMS, MOB_NUM);
Thread Bal3 = new Thread(sendWelcomesms2);
Bal3.start();
Thread q = new Thread(new GupShupSMSUtill(PasswordSMS, MOB_NUM));
q.start();
latch.await(); // Wait
}
catch (InterruptedException e)
{
e.printStackTrace();
}
At the end of the Thread "q":
latch.countDown(); // stop to wait
Hint - Don't use Thread.sleep(x) in this case.
You are sleeping the current thread, before you issue the startcommand for q.
You probably want to issue the sleep inside GupShupSMSUtill() (maybe change its signature to something like GupShupSMSUtill(PasswordSMS,MOB_NUM, sleeptime) to be able to control how long it sleeps).
Im working on a elevator simulator, in wich i have to simulate the work of 4 elevators in a building. Well, at first i thought it was easy, 4 threads and its all good. but im running into trouble because my threads won't run at the same time, even with infinite cycles only one thread runs at a time.
#Override
public void run() {
while (true)
{
int i = rand.nextInt(p1.getNFloors());
building.getFloors().get(i).putPersons();
System.out.println(building.toString());
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
Logger.getLogger(Relogio.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
and on a seperate thread :
#Override
public void run() {
while (true)
{
for (int i = 0; i < building.getFloors().size(); i++)
{
if (building.getFloors().get(i).getPersons().size() != 0)
{
building.getFloors().get(i).callElevator(); //this should call 1 elevator
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
Logger.getLogger(Thread1.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
}
and i have 4 instances of this thread running (therefor i have 4 elevators)
the problem is: only 1 thread runs at a time, so only 1 elevator at a time.
btw, the callElevator method gets the elevator from an arrayList in wich i have 4 elevators stored. the condition that needs to be met is if the elevator is stopped he can be called.
the way i start the threads:
the first thread (the one that puts people in the floors): thread.start();
and after that , i initialize 4 instances of the thread that calls the elevators.
so it looks like this:
Simulator s1 = new Simulator();
ElevatorThread et1 = new ElevatorThread();
ElevatorThread et2 = new ElevatorThread();
ElevatorThread et3 = new ElevatorThread();
ElevatorThread et4 = new ElevatorThread();
s1.start();
et1.start();
et2.start();
et3.start();
et4.start();
both threads extends Thread.
any tips?