I just started learning "multithreading" in JAVA and it seams I don't understand how keyword "synchronized" works.
I had four examples and they're very alike (in my opinion), and I don't understand why I get every time different results.
public class BufferThread1 {
static int counter = 0;
static StringBuffer s = new StringBuffer();
public static void main(String args[]) throws InterruptedException {
new Thread() {
public void run() {
synchronized (s) {
while (BufferThread1.counter++ < 3) {
s.append("A");
System.out.print("> " + counter + " ");
System.out.println(s);
try {
Thread.sleep(500);
} catch (InterruptedException ex) {
Logger.getLogger(BufferThread1.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
}.start();
Thread.sleep(100);
while (BufferThread1.counter++ < 6) {
System.out.print("< " + counter + " ");
s.append("B");
System.out.println(s);
}
}
}
Result:
run:
> 1 A
< 2 > 3 AA
AAB
< 5 AABB
< 6 AABBB
public class BufferThread2 {
static int counter = 0;
static StringBuilder s = new StringBuilder();
public static void main(String args[]) throws InterruptedException {
new Thread() {
public void run() {
synchronized (s) {
while (BufferThread2.counter++ < 3) {
s.append("A");
System.out.print("> " + counter + " ");
System.out.println(s);
try {
Thread.sleep(500);
} catch (InterruptedException ex) {
Logger.getLogger(BufferThread2.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
}.start();
Thread.sleep(100);
while (BufferThread2.counter++ < 6) {
System.out.print("< " + counter + " ");
s.append("B");
System.out.println(s);
}
}
}
Result:
run:
> 1 A
< 2 AB
< 3 ABB
< 4 ABBB
< 5 ABBBB
< 6 ABBBBB
public class BufferThread3 {
static int counter = 0;
static StringBuffer s = new StringBuffer();
public static void main(String args[]) throws InterruptedException {
new Thread() {
public void run() {
synchronized (s) {
while (BufferThread3.counter++ < 3) {
s.append("A");
System.out.print("> " + counter + " ");
System.out.println(s);
try {
Thread.sleep(500);
} catch (InterruptedException ex) {
Logger.getLogger(BufferThread3.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
}.start();
Thread.sleep(100);
synchronized (s) {
while (BufferThread3.counter++ < 6) {
System.out.print("< " + counter + " ");
s.append("B");
System.out.println(s);
}
}}
}
Result:
run:
> 1 A
> 2 AA
> 3 AAA
< 5 AAAB
< 6 AAABB
Of course, I skipped
import java.util.logging.Level;
import java.util.logging.Logger;
I just don't realise how these examples work and synchronized here !
I do hope that someone help me.
Your < and > label which thread is running here.
> 1 A
Your background thread is running only and prints this line as expected.
< 2
The main thread prints the counter 2 but cannot acquire the lock on s so it blocks.
> 3 AA
The background thread increments the counter again and prints 3 and a second A. On the next iteration it exits and counter == 4 As the thread exits, it releases the lock.
AAB
The main thread can now acquire the lock and append("B")
< 5 AABB
The main thread increments the counter to 5 and adds another B
StringBuffer is a pet hate of mine which was replaced more thna ten years ago by StringBuidler. It is almost impossible to implement a useful thread safe class using it and when people have tried, it has meant the class wasn't really thread safe. Note: SimpleDateFormat uses StringBuffer and it is not thread safe.
Let's try a simpler example that gets at what synchronized does without such an overly complicated class.
Consider the following Runnable task:
public class Task implements Runnable {
private final int id;
public Task(int id) {
this.id = id;
}
public void run() {
for(int i = 0; i < 5; i++) {
System.out.println("Task " + id + " prints " + i);
}
}
}
Then let's try running it with this main method:
public static void main(String[] args) {
Thread t1 = new Thread(new Task(1));
Thread t2 = new Thread(new Task(2));
t1.start();
t2.start();
}
The output could look something like this:
Task 1 prints 0
Task 1 prints 1
Task 1 prints 2
Task 1 prints 3
Task 1 prints 4
Task 2 prints 0
Task 2 prints 1
Task 2 prints 2
Task 2 prints 3
Task 2 prints 4
But it could also look like this:
Task 1 prints 0
Task 2 prints 0
Task 2 prints 1
Task 1 prints 1
Task 1 prints 2
Task 1 prints 3
Task 1 prints 4
Task 2 prints 2
Task 2 prints 3
Task 2 prints 4
Task 2 prints 4
The truth is, you have no guarantees about the order in which the two Tasks execute commands (with respect to each other. You still do know that each task will print 0...4 in order). The fact that t1.start() comes before t2.start() means nothing.
The synchronized command allows for some control over which thread executes when. Essentially, the command synchronized(obj) {....} means that at most one thread is allowed to execute the commands in the block (within the {...}) at a time. This is know as mutual exclusion.
A nice way to think about it is as a locked room with a single key hanging outside on the wall. In order to get into the room, you have to take the key off the wall, unlock the door, go into the room, and lock it from the inside. Once you are done doing whatever you are doing in the room, you unlock the door from the inside, go outside, lock the door from the outside, and hang the key up. It is clear that while you are in the room no one else can join you, as the door is locked and you currently hold the only key to get in.
To illustrate, consider the following improved task class:
public class SynchronizedTask implements Runnable {
private final Object lock;
private final int id;
public Task(int id, Object lock) {
this.id = id;
this.lock = lock;
}
public void run() {
synchronized(lock) {
for(int i = 0; i < 5; i++) {
System.out.println("Task " + id + " prints " + i);
}
}
}
}
And run it with the following modified main method:
public static void main(String[] args) {
Object lock = new Object();
Thread t1 = new Thread(new Task(1, lock));
Thread t2 = new Thread(new Task(2, lock));
t1.start();
t2.start();
}
We still don't know whether t1 or t2 will enter the synchronized block first. However, once has entered, the other must wait for it to finish. Thus, there are exactly two possible outputs of this code. Either t1 gets in first:
Task 1 prints 0
Task 1 prints 1
Task 1 prints 2
Task 1 prints 3
Task 1 prints 4
Task 2 prints 0
Task 2 prints 1
Task 2 prints 2
Task 2 prints 3
Task 2 prints 4
Or t2 gets in first:
Task 2 prints 0
Task 2 prints 1
Task 2 prints 2
Task 2 prints 3
Task 2 prints 4
Task 1 prints 0
Task 1 prints 1
Task 1 prints 2
Task 1 prints 3
Task 1 prints 4
It is important to note that this behavior only worked as desired because we used the same lock object for both Tasks. If we had run the following code instead:
public static void main(String[] args) {
Thread t1 = new Thread(new Task(1, new Object()));
Thread t2 = new Thread(new Task(2, new Object()));
t1.start();
t2.start();
}
We would have identical behavior to the original un-synchronized code. This is because we now have a room with two (or really, infinite if we replicate our thread initialization) keys hanging outside. Thus while t1 is inside the synchronized block, t2 can just use its own key to get in, defeating the whole purpose.
First example shown by Mr. Lawrey.
In the second example the "Background" thread only gets to do one print of and since StringBuilder is used this time instead of StringBuffer the main thread will not block while trying to print "s", hence only 1 A.
In the third example the main thread is blocked until the background thread terminates because you start the background thread before the main thread's loop. Thus the background thread will get 3 loops done and hence the 3 A's.
Though I suspect these are artificial examples for learning purposes it should still be noted that sleeping inside a synchronized block is NOT a good idea as this will not release the lock.
Related
I have been working on a school assignment which is about multithreading in Java. One of the tasks that I am stuck on is that we need to create multiple threads in different groups, and once there are 4 threads in each group, only then they can be released to work in unison, otherwise they have to be put on hold/waiting. For example:
Thread a,b,c joins group 7, they are all put on hold/waiting.
Thread d joins group 7, all four threads (a,b,c,d) are signaled to be terminated.
Thread e,f,g,h,i joins group 8, in this case e,f,g,h will be signalled to be terminated while thread i is put on waiting.
Thread j joins group 7, it is put on for waiting.
That is the general task which I'm done with. The task I am working on requires us to release the INITIAL first 4 threads of a group, and the rest should wait until 4 of the previous threads have called finished().
For example, 3 threads join group 65, they are put on wait. Another thread joins group 65 and all 4 threads are released together. Now 4 threads are working (terminated). Now thread e,f,g,h,i,j,k,l join group 65. All of them are put to wait until e,f,g,h have called finished() method.
Here is what I have done so far:
ExtrinsicSync.java:
import java.util.HashMap;
import java.util.concurrent.locks.ReentrantLock;
public class ExtrinsicSync {
private HashMap<Integer, ConditionWrapper> groupThreadCount;
private ReentrantLock monitor;
private int count = 0;
ExtrinsicSync() {
groupThreadCount = new HashMap<>();
monitor = new ReentrantLock();
}
#Override
public void waitForThreadsInGroup(int groupId) {
monitor.lock();
if (!groupThreadCount.containsKey(groupId))
groupThreadCount.put(groupId, new ConditionWrapper(monitor.newCondition()));
ConditionWrapper condWrapper = groupThreadCount.get(groupId);
condWrapper.setValue(condWrapper.getValue() + 1);
if(condWrapper.getValue() == 4 && condWrapper.getInitialStatus())
{
condWrapper.getCondition().signalAll();
condWrapper.setInitialStatus(false);
System.out.println("Terminating group: " + groupId + "FROM INITIAL STATE: " + ++count);
} else {
System.out.println("Putting thread from group: " + groupId + " on wait: " + ++waitcount);
try { condWrapper.getCondition().await(); }
catch (InterruptedException e) { e.printStackTrace(); }
}
monitor.unlock();
}
#Override
public void finished(int groupId) {
monitor.lock();
ConditionWrapper condWrapper = groupThreadCount.get(groupId);
if(!condWrapper.getInitialStatus())
{
condWrapper.setFinishedCount(condWrapper.getFinishedCount() + 1);
System.out.println("Group: " + groupId + "FINISHED COUNT: " + condWrapper.getFinishedCount());
if(condWrapper.getFinishedCount() == 4)
{
condWrapper.setFinishedCount(0);
condWrapper.getCondition().signalAll();
System.out.println("Terminating threads for group: " + groupId + ": " + ++count);
}
}
monitor.unlock();
}
ExtrinsicSyncTest.java:
import org.junit.Test;
import java.util.EnumMap;
class TestTask1 implements Runnable{
final int group;
final ExtrinsicSync s1;
TestTask1(int group, ExtrinsicSync s1)
{
this.group = group;
this.s1 = s1;
}
public void run() { s1.waitForThreadsInGroup(group); s1.finished(group); }
}
public class ExtrinsicSyncTest {
#Test
public void testPhaseThreethreads() {
int nThreads = 22;
Thread t[] = new Thread[nThreads];
final ExtrinsicSync s1 = new ExtrinsicSync();
for(int i = 0; i < nThreads/2; i++)
(t[i] = new Thread(new TestTask1(66, s1))).start();
for(int i = nThreads/2; i < nThreads; i++)
(t[i] = new Thread(new TestTask1(70, s1))).start();
for (Thread ti : t)
{
try { ti.join(100); }
catch (Exception e) { System.out.println(e); }
}
EnumMap<Thread.State, Integer> threadsInThisState = new EnumMap<>(Thread.State.class);
for (Thread.State s : Thread.State.values())
threadsInThisState.put(s, 0);
for (Thread ti : t)
{
Thread.State state = ti.getState();
int n = threadsInThisState.get(state);
threadsInThisState.put(state, n + 1);
}
System.out.println("threadsInThisState: " + threadsInThisState.toString() );
}
}
ConditionWrapper.java:
import java.util.concurrent.locks.Condition;
public class ConditionWrapper {
private Condition cond;
private Integer value;
private Integer finishedCount;
private boolean initialThreads;
public ConditionWrapper(Condition condition)
{
this.cond = condition;
this.value = 0;
this.finishedCount = 0;
this.initialThreads = true;
}
// Returns the condition object of current request
public Condition getCondition()
{
return this.cond;
}
// Gets the current counter of threads waiting in this queue.
public Integer getValue()
{
return this.value;
}
// Sets the given value. Used for resetting the counter.
public void setValue(int value) { this.value = value; }
// Sets the counter to help keep track of threads which called finished() method
public void setFinishedCount(int count) { this.finishedCount = count; }
// Gets the finished count.
public Integer getFinishedCount() { return this.finishedCount; }
// This flag is to identify initial threads of a group
public boolean getInitialStatus() { return initialThreads; }
public void setInitialStatus(boolean val) { this.initialThreads = val; }
}
The problem I am having is that I am able to release the first four threads of every group, but somehow, somewhere 2 threads are being terminated randomly and I cannot figure out what is going on. For example, with 22 threads test case above divided into two groups, only 8 threads should be terminated while the rest of them wait.
But here 10 threads are being terminated instead. I do not understand what is going on. I have stripped the code down to bare minimum as best as I could.
The problem is that for the not initial threads (getInitialStatus==false) you do not signal the other threads but you still terminate them when you reached four of them. So this is what happens:
first three threads increase the count and wait
the fourth thread reaches count == 4 and sets initial = false and signals all the other threads and sets the count to zero
the next three threads increase the count by one
the 8 threads reaches count == 4 and gets terminated. Since getInitialStatus==false this thread does not notify the other threads.
so 4*2 threads + 2 threads get terminated. Exactly the count you have seen in your tests.
Here is a potential way to implement this:
use a flag canExecute in each thread or task
use a method calculateState to calculate the current state and set the flag to true if a thread is allowed to execute.
store all threads which are waiting in a list or something similar
So your task would look like this:
Task
boolean canExeute
The method waitForThreadsInGroup then lookslike this:
waitForThreadsInGroup
monitor.lock();
add task to list
calculateTaskState
condition.notifyAll
while( ! task.canExcecute )
{
condition.await.
}
monitor.unlock();
The finish method looks similar:
finish
monitor.lock();
decrement finish count
calculateTaskState
condition.notifyAll
monitor.unlock();
And calculateTaskState
calculateTaskState
if( finishCount == 0)
{
if( taskList.size >= 4 )
{
set 4 tasks in this list to can execute and remove them from the list
}
}
So the trick is to separate the logic into three steps:
the action, for example reducing the finish count
the calculation of the new state. And deciding for each thread if it is allowed to execute
And the waiting of the threads. Each thread needs to wait on its own flag
This question already has answers here:
Java. The order of threads execution
(2 answers)
Closed 3 years ago.
Thread two is running first on output though I've called start() method of thread1 at first. Why this is happening?
Output:
Thread two running: 0
Thread two running: 1
Thread one running: 0
Thread two running: 2
....
package interfacetest;
class thread1 extends Thread {
public void run() {
for(int i=0; i<10; i++) {
System.out.println("Thread one running: " +i);
}
}
}
class thread2 extends Thread {
public void run() {
for(int j=0; j<10; j ++) {
System.out.println("Thread two running: " +j);
}
}
}
class InterfaceTest {
public static void main(String[] args) {
thread1 t1 = new thread1();
thread2 t2= new thread2();
t1.start();
t2.start();
}
}
When we start thread, java starts execution of run method in separate thread. And thread ordering is never gauranteed. Here as you are simply starting 2 different threads no gaurantee that they will be executed in sequence.
Suppose I have 10 threads that are incrementing a variable by 1. Suppose Thread-1 increments a variable first, and then Thread-2 and Thread-3 and consecutively. after all the 10 Threads have incremented the variable. I need to decrement the same variable in a manner.
Decrementing, if Thread-1 incremented the variable first of all, then it should decrement at last.
We need to do this without setting thread priority.
you can use a lot of ways, here's one for example:
public class Main {
public static void main(String[] args) throws Exception {
for(int i=0;i<10;i++){
final int _i=i;
Thread t = new Thread(new T(_i));
t.start();
}
}
public static class T implements Runnable{
int threadNumber;
public T(int threadNumber) {
this.threadNumber=threadNumber;
}
#Override
public void run() {
increase(this);
}
}
static Thread[] threads = new Thread[10];
static int number =0;
static Object generalLock=new Object();
public static void increase(T t){
int myNumber=0;
synchronized (generalLock){
myNumber=number;
System.out.println("i am "+number+" incrementing, my real number "+t.threadNumber);
threads[number]=Thread.currentThread();
number++;
}
while (threads[9]==null){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
for(int i=9;i>myNumber;i--){
try {
threads[i].join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
synchronized (generalLock){
System.out.println("i am "+number+" decrementing, my real number "+t.threadNumber);
number--;
}
}
}
output example:
i am 0 incrementing, my real number 1
i am 1 incrementing, my real number 8
i am 2 incrementing, my real number 9
i am 3 incrementing, my real number 7
i am 4 incrementing, my real number 6
i am 5 incrementing, my real number 5
i am 6 incrementing, my real number 0
i am 7 incrementing, my real number 4
i am 8 incrementing, my real number 3
i am 9 incrementing, my real number 2
i am 9 decrementing, my real number 2
i am 8 decrementing, my real number 3
i am 7 decrementing, my real number 4
i am 6 decrementing, my real number 0
i am 5 decrementing, my real number 5
i am 4 decrementing, my real number 6
i am 3 decrementing, my real number 7
i am 2 decrementing, my real number 9
i am 1 decrementing, my real number 8
i am 0 decrementing, my real number 1
Note: you can use simple Runnable, I create T class to show the thread number in order to print it while incrementing/decrementing
This seems to work. Essentially I create the 10 threads and specially identify one of them using an enum. They all try to increment the shared integer, identifying themselves. The incrementer detects the first increment by noticing the transition to 1 and if it's a Special thread it returns true .
There's also a CountDownLatch used to synchronise all of the threads to ensure there is at least a chance of the two alternatives. I get about 8600 out of the 10000 test runs where the Special got there first. This value will vary depending on many variables.
enum Who {
Special, Normal;
}
class PriorityIncrementer {
final AtomicInteger i = new AtomicInteger(0);
boolean inc(Who who) {
return i.incrementAndGet() == 1 && who == Who.Special;
}
public void dec() {
i.decrementAndGet();
}
}
class TestRunnable implements Runnable {
final Who me;
final PriorityIncrementer incrementer;
final CountDownLatch latch;
public TestRunnable(PriorityIncrementer incrementer, CountDownLatch latch, Who me) {
this.incrementer = incrementer;
this.latch = latch;
this.me = me;
}
#Override
public void run() {
// Wait for all others to get here.
latch.countDown();
try {
// Wait here until everyone os waiting here.
latch.await();
// Do it.
if(incrementer.inc(me)) {
// I was first and special, decrement after.
incrementer.dec();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private boolean test(int count) throws InterruptedException {
Thread[] threads = new Thread[count];
// The shared incrementer.
PriorityIncrementer incrementer = new PriorityIncrementer();
// Arrange for all of them to synchronise.
CountDownLatch latch = new CountDownLatch(threads.length+1);
// One special.
threads[0] = new Thread(new TestRunnable(incrementer, latch, Who.Special));
// The rest are normal.
for(int i = 1; i < threads.length; i++) {
threads[i] = new Thread(new TestRunnable(incrementer, latch, Who.Normal));
}
// Start them up.
for (Thread thread : threads) {
thread.start();
}
// Wait a moment.
Thread.sleep(1);
// Start them all going.
latch.countDown();
// Wait for them to finish.
for (Thread thread : threads) {
thread.join();
}
// Who won?
return incrementer.i.get() < count;
}
public void test() throws InterruptedException {
final int tests = 10000;
int specialWasFirstCount = 0;
for (int i = 0; i < tests; i++) {
if(test(10)) {
specialWasFirstCount += 1;
}
}
System.out.println("Specials: "+specialWasFirstCount+"/"+tests);
}
package testpkg;
public class ThreadOrdering {
public static void main(String[] args) {
MyRunnable[] threads = new MyRunnable[10];//index 0 represents thread 1;
for(int i=0; i < 10; i++)
threads[i] = new MyRunnable(i, threads);
//threads[0] = new MyRunnable(0, threads);
new Thread(threads[0]).start();
}
}
class MyRunnable implements Runnable {
int threadNumber;
MyRunnable[] threads;
public MyRunnable(int threadNumber, MyRunnable[] threads) {
this.threadNumber = threadNumber;
this.threads = threads;
}
public void run() {
synchronized (this) {
if(this.threadNumber!=10)
new Thread(threads[this.threadNumber]).start();
this.threadNumber++;
}
System.out.println("the thread " + Thread.currentThread().getName() + " with num " + this.threadNumber);
}
}
I actually should not be incrementing threadNumber, but if I don't it goes into a infinite loop, and if I do increment 19 threads are created instead of 10
It's the threadNumber++ that's causing duplicate threads to be started.
If you use new Thread(threads[this.threadNumber+1]).start(); (and remove the threadNumber++) only 10 are started.
Let's examine the logic:
new Thread(threads[0]).start(); // Start the first thread
// Inside the first thread's run
if(0 != 10)
new Thread(threads[0]).start(); // Oh noes, we restarted the first thread/runnable
this.threadNumber++; // We restarted the thread, AND incremented its threadnumber!
// Inside the first runnable's run AGAIN!
if(1 != 10)
new Thread(threads[1]).start(); // NOW we started the second thread
this.threadNumber++; // First thread's threadnumber is now 2, but we didn't restart it so it won't run again
So every thread except for the last one (where 10 != 10 returns false) restarts itself once, giving you the total of 19 threads.
Join is not working. I get a wrong output. Here is the code:
package Test;
public class Test {
public static void main(String[] args){
System.out.println("Hello world!");
ThreadTest t1 = new ThreadTest("1");
ThreadTest t2 = new ThreadTest("2");
t1.start();
try{
t1.join();
System.out.println("OK!");
}catch( Exception e){
e.getMessage();
System.out.println("Fail!");
}
t2.start();
}
}
package Test;
public class ThreadTest extends Thread{
private Thread t;
private String name;
ThreadTest (String name){
this.name = name;
}
public void run(){
for(int i = 0; i<=10; i++){
System.out.println("Tread: " + name + " " + i);
}
}
public void start(){
if(t == null){
t = new Thread(this, name);
t.start();
}
}
}
I get the following output:
Hello world!
OK!
Tread: 1 0
Tread: 1 1
Tread: 1 2
Tread: 1 3
Tread: 1 4
Tread: 2 0
Tread: 2 1
Tread: 2 2
Tread: 1 5
Tread: 2 3
Tread: 1 6
Tread: 2 4
Tread: 1 7
Tread: 2 5
Tread: 1 8
Tread: 2 6
Tread: 1 9
Tread: 2 7
Tread: 1 10
Tread: 2 8
Tread: 2 9
Tread: 2 10
This is wrong! Thread 2 should start after thread 1 finished and not in between, because of the join() method.
What the other answers tell you is that your program creates four Thread instances, but it only uses two of them as threads. The Thread instance that you join is one of the two that your program never starts.
Part of your confusion is due to the fact that your Thread subclass has a method named start(), but that method doesn't do what Thread.start() does.
OK, that's all bad, but here's a deeper problem:
Q: What's the point of doing this:
Thread t = new Thread(...);
t.start();
t.join();
A: There is no point in doing that. The point of using threads---the entire point---is that when one thread starts another thread, the first thread can then do something else while the new thread is running:
Thread t = new Thread(...);
t.start();
doSomethingElse(...)
t.join();
You're not joining on the Thread, but on the object ThreadTest.
The method start is creating a new Thread and start it.
I suggest to add a method like this in ThreadTest and call it:
public void joinThread(){
if(t != null){
t.join();
}
}
You are creating a new Thread in this method
public void start(){
if(t == null){
t = new Thread(this, name);
t.start();
}
}
It should be like this
public class ThreadTest extends Thread{
ThreadTest (String name){
super(name);
}
public void run(){
for(int i = 0; i<=10; i++){
System.out.println("Tread: " + getName() + " " + i);
}
}
}
//t.join (10000) add a value large, so that t1 job is over
try{
t1.join(10000);
System.out.println("OK!");
}catch( Exception e){
e.getMessage();
System.out.println("Fail!");
}