Unit test the thread safety of a singleton class in Java? - java

Let's imagine I have the following java class :
static class Singleton {
static Singleton i;
static Singleton getInstance() {
if (i == null) {
i = new Singleton();
}
return i;
}
}
Now, we all know this will work, but - it apparently is not thread safe - I am not actually trying to fix the thread safety - this is more of a demo, my other class is identical, but uses a mutex and synchronization - the unit test will be ran against each to show that one is thread safe, and the other, is not. What might the unit test which would fail if getInstance is not thread safe look like?

Well, race conditions are by nature probabilistic so there's no deterministic way to truly generate a race condition. Any possible way against your current code would need to be run many times until the desired outcome is achieved. You can enforce a loose ordering of access on i by making a mock singleton to test against to simulate what a certain condition might look like, though. Rule of thumb with synchronization is preventative measures beat trying to test and figure out what's wrong after bad code is mangled in a code base.
static class Singleton {
static Singleton i;
static Singleton getInstance(int tid) {
if (i == null) {
if (tid % 2 == 0) i = new Singleton()
}
return i;
}
}
So certain threads will write to i and other threads will read i as if they reached "return i" before "the even thread id's were able to check and initialize i" (sort of, not exactly, but it simulates the behavior). Still, there's a race between the even threads in this case because the even threads may still write to i after another reads null. To improve, you'd need to implement thread safety to force the condition where one thread reads i, gets null, while the other thread sets i to new Singleton() a thread-unsafe condition. But at that point you're better off just solving the underlying issue (just make getInstance thread safe!)
TLDR: there are infinitely many race conditions that can occur in a unsafe function call. You can mock the code to generate a mock of a specific race condition (say, between just two threads) but it's not feasible to just blanket test for "race conditions"

This code worked for me.
The trick is that it is probabilistic like said by other users.
So, the approach that should be taken is to run for a number of times.
public class SingletonThreadSafety {
public static final int CONCURRENT_THREADS = 4;
private void single() {
// Allocate an array for the singletons
final Singleton[] singleton = new Singleton[CONCURRENT_THREADS];
// Number of threads remaining
final AtomicInteger count = new AtomicInteger(CONCURRENT_THREADS);
// Create the threads
for(int i=0;i<CONCURRENT_THREADS;i++) {
final int l = i; // Capture this value to enter the inner thread class
new Thread() {
public void run() {
singleton[l] = Singleton.getInstance();
count.decrementAndGet();
}
}.start();
}
// Ensure all threads are done
// The sleep(10) is to be somewhat performant, (if just loop,
// this will be a lot slow. We could use some other threading
// classes better, like CountdownLatch or something.)
try { Thread.sleep(10); } catch(InterruptedException ex) { }
while(count.get() >= 1) {
try { Thread.sleep(10); } catch(InterruptedException ex) { }
}
for( int i=0;i<CONCURRENT_THREADS - 1;i++) {
assertTrue(singleton[i] == singleton[i + 1]);
}
}
#Test
public void test() {
for(int i=0;i<1000;i++) {
Singleton.i = null;
single();
System.out.println(i);
}
}
}
This have to make some change in the Singleton design pattern. That the instance variable is now accessible in the Test class. So that we could reset the Singleton instance available to null again every time the test is repeated, then we repeat the test 1000 times (if you have more time, you could make it more, sometimes finding an odd threading problem require that).

In some cases this solution works. Unfortunately its hard to test singleton to provoke thread unsafe.
#Test
public void checkThreadUnSafeSingleton() throws InterruptedException {
int threadsAmount = 500;
Set<Singleton> singletonSet = Collections.newSetFromMap(new ConcurrentHashMap<>());
ExecutorService executorService = Executors.newFixedThreadPool(threadsAmount);
for (int i = 0; i < threadsAmount; i++) {
executorService.execute(() -> {
Singleton singleton = Singleton.getInstance();
singletonSet.add(singleton);
});
}
executorService.shutdown();
executorService.awaitTermination(1, TimeUnit.MINUTES);
Assert.assertEquals(2, singletonSet.size());
}

Related

double check lock without volatile is wrong?

i use jdk1.8. i think that double check lock without volatile is right.
I use countdownlatch test many times and the object is singleton.
How to prove that it must need “volatile”?
update 1
Sorry, my code is not formatted, because I can’t receive some JavaScript
public class DCLTest {
private static /*volatile*/ Singleton instance = null;
static class Singleton {
public String name;
public Singleton(String name) {
try {
//We can delete this sentence, just to simulate various situations
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.name = name;
}
}
public static Singleton getInstance() {
if (null == instance) {
synchronized (Singleton.class) {
if (null == instance) {
instance = new Singleton(Thread.currentThread().getName());
}
}
}
return instance;
}
public static void test() throws InterruptedException {
int count = 1;
while (true){
int size = 5000;
final String[] strs = new String[size];
final CountDownLatch countDownLatch = new CountDownLatch(1);
for (int i = 0; i < size; i++) {
final int index = i;
new Thread(()->{
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
Singleton instance = getInstance();
strs[index] = instance.name;
}).start();
}
Thread.sleep(100);
countDownLatch.countDown();
Thread.sleep(1000);
for (int i = 0; i < size-1; i++) {
if(!(strs[i].equals(strs[i+1]))){
System.out.println("i = " + strs[i] + ",i+1 = "+strs[i+1]);
System.out.println("need volatile");
return;
}
}
System.out.println(count++ + " times");
}
}
public static void main(String[] args) throws InterruptedException {
test();
}
}
The key problem that you are not seeing is that instructions can be reordered. So the order they are in the source code, isn't the same as they are applied on memory. CPU's and compilers are the cause or this reordering.
I'm not going through the whole example of example of double checked locking because many examples are available, but will provide you just enough information to do some more research.
if you would have the following code:
if(singleton == null){
synchronized{
if(singleton == null){
singleton = new Singleton("foobar")
}
}
}
Then under the hood something like this will happen.
if(singleton == null){
synchronized{
if(singleton == null){
tmp = alloc(Singleton.class)
tmp.value = "foobar"
singleton = tmp
}
}
}
Till so far, all is good. But the following reordering is legal:
if(singleton == null){
synchronized{
if(singleton == null){
tmp = alloc(Singleton.class)
singleton = tmp
tmp.value = "foobar"
}
}
}
So this means that a singleton that hasn't been completely constructed (the value has not yet been set) has been written to the singleton global variable. If a different thread would read this variable, it could see a partially created object.
There are other potential problems like atomicity (e.g. if the value field would be a long, it could be fragmented e.g. torn read/write). And also visibility; e.g. the compiler could optimize the code so that the load/store from memory is optimized-out. Keep in mind that thinking in term of reading from memory instead of cache, is fundamentally flawed and the most frequently encountered misunderstandings I see on SO; even many seniors get this wrong. Atomicity, visibility and reordering are part of the Java memory model, and making the singleton' variable volatile, resolves all these problems. It removes the data race (you can look it up for more details).
If you want to be really hardcore, it would be sufficient to place a [storestore] barrier between the creation of an object and the assignment to the singleton and a [loadload] barrier on the reading side and make sure you use a VarHandle with opaque for the singleton.
But this goes well beyond what most engineers understand and it won't make much of a performance difference in most situations.
If you want to check if something can break, please check out JCStress:
https://github.com/openjdk/jcstress
It is a great tool and can help you help you to show that your code is broken.
How to prove that it must need “volatile”?
As a general rule, you cannot prove correctness of a multi-threaded application by testing. You may be able to prove incorrectness, but even that is not guaranteed. As you are observing.
The fact that you haven't succeeded in making your application fail is not a proof that it is correct.
The way to prove correctness is to do a formal (i.e. mathematical) happens before analysis.
It is fairly straightforward to show that when the singleton is not volatile there are executions in which there is a missing happens before. This may lead to an incorrect outcome such as the initialization happening more than once. But it is not guaranteed that you will get an incorrect outcome.
The flip-side is that if a volatile is used, the happens before relationships combined with the logic of the code are sufficient to construct a formal (mathematical) proof that you will always get a correct outcome.
(I am not going to construct the proofs here. It is too much effort.)

How to test that Java class is thread safe?

Let's take this simple class:
public class CounterService {
private volatile Counter counter;
public CounterService(Counter counter) {
this.counter = counter;
}
public long getCounterValue() {
System.out.println("GET: " + this.counter.counter + " in thread " +
Thread.currentThread().getName());
return this.counter.counter;
}
public long setCounterValue(long newValue) {
this.counter = this.counter.updateCounter(newValue);
System.out.println("--set: " + newValue + " in thread " +
Thread.currentThread().getName());
return this.counter.counter;
}
}
public class Counter {
public final long counter;
public Counter(long counter) {
this.counter = counter;
}
public Counter updateCounter(long i) {
return new Counter(i);
}
}
Now I want to write the unit test, that will always pass, if the CounterService is thread safe (eg. when I set get and set methods synchronized). I belive that writing a test, which will always fail if this class isn't thread safe, may be impossible.
I tried with something like this:
#Test
public void multipleThreadSetAndGetShouldCorrectValue() throws ExecutionException, InterruptedException {
int threads = 10;
final Counter counter = new Counter(0);
final CounterService counterService = new CounterService(counter);
CountDownLatch latch = new CountDownLatch(1);
ExecutorService executorService = Executors.newFixedThreadPool(threads);
Collection<Future<Long>> results = new ArrayList<>();
AtomicLong sequence = new AtomicLong(0);
for (int i = 0; i < threads; i++) {
results.add(executorService.submit(() -> {
latch.await(1, TimeUnit.SECONDS);
latch.countDown();
counterService.setCounterValue(sequence.getAndIncrement());
return counterService.getCounterValue();
}));
}
final Set<Long> uniqueResult = new HashSet<>();
for (Future<Long> result : results) {
uniqueResult.add(result.get());
}
assertEquals(threads, uniqueResult.size());
}
But this test will occasionally fail even if the CounterService is thread safe.
How to write unit test that will always pass when the class is thread safe? How to write test to check, that get method returns the last set value, even if it was modified by another thread?
First, your Counter class is pointless. The updateCounter method doesn't update, it returns a new object. So just delete the Counter class and use long in your CounterService.
There then remains the question as to what CounterService is for. It just wraps a long.
But disregarding that. No - you can't really write a test to prove that something is not thread-safe as multi-threading problems are not deterministic. You could insert delays into places where you know race conditions might occur, but that only works if you already know it isn't thread-safe in a particular place and you want to prove it. But if you don't know where the problem is you might not be able to insert the delays in the right place to prove the possible problem does exist.
By the same token, you can't really prove that it is correct either, although again you can increase your chances by inserting sleeps between operations to force problems. But it may not work and you are not testing the real-world scenario.
Your test is failing because you don't understand what synchronized does and what thread-safely implies.
In your test, you are setting a counter value and then getting it in the next line. If you synchronize the set and the get, all that means is that the individual get and set operations are thread-safe. It doesn't mean that you can call get and set separately and that get will return the same value that the previous set used.
If you want to set something and then get the same value back again safely you have to wrap the get and the set calls in a synchronized block.
synchonized(this) { // get must return same thing that was set
set
get
}
I strongly recommend that you focus on understanding what your program needs to achieve and what thread-safety and sychronization means in that context. Otherwise, you won't be able to develop a correct test anyway.

How to test something in Multi-Threaded Environment using Java [duplicate]

This question already has answers here:
How should I unit test multithreaded code?
(29 answers)
Closed 5 years ago.
How do I test something like this in multithreaded environment. I know it's gonna fail, cause this code is not thread-safe. I just wanna know how can i prove it? Creating bunch of threads and trying to add with those different threads? This code is intentionally not written properly cause of testing purposes !!!
public class Response_Unit_Manager {
private static HashMap<String, Response_Unit> Response_Unit_DB =
new HashMap<> ();
/**
*
* This subprogram adds a new Response_Unit to the data store. The
* new response unit must be valid Response_Unit object and it's ID must be
* unique (i.e., must not already exist in the data store.
*
* Exceptions Thrown: Null_Object_Exception
*/
public static void Add_Response_Unit (Response_Unit New_Unit)
throws Null_Object_Exception, Duplicate_Item_Exception {
String Unit_ID = New_Unit.Unit_ID ();
if (New_Unit == null)
throw new Null_Object_Exception ();
else if (Response_Unit_Exists (Unit_ID))
throw new Duplicate_Item_Exception (Unit_ID);
else
Response_Unit_DB.put (Unit_ID, New_Unit);
} //end Add_Response_Unit
You may get lucky and see a failure when running a test, but non-failing code doesn't mean that it's thread-safe code. The only automated ways to check thread-safety is with some static analysis tools that let you put annotations on methods/classes and scan for potential issues. For example, I know FindBugs support some annotations and does concurrency checking based on them. You should be able to apply this to your single Tester class. There is still a lot of room for improvement in the industry on this topic, but here are some current examples:
http://robertfeldt.net/publications/grahn_2010_comparing_static_analysis_tools_for_concurrency_bugs.pdf
http://homepages.inf.ed.ac.uk/dts/students/spathoulas/spathoulas.pdf
As others have noted, you can't write a test that will guarantee failure as the thread schedule might "just work out", but you can write tests that have a very low probability of passing if there are thread safety issues. For example, you're code attempts to disallow duplicate items in your DB but due to thread safety issues it can't do that. So spawn a ton of threads, have them all wait on a CountdownLatch or something to maximize your chances of triggering the race, then have them all try to insert the same item. Finally you can check that (a) all but one thread saw a Duplicate_Item_Exception and (b) Response_Unit_DB contains only a single item. For these kinds of tests you can also run it several times (in the same test) to maximize your chances of triggering the issue.
Here's an example:
#Test
public void testIsThreadSafe() {
final int NUM_ITERATIONS = 100;
for(int i = 0; i < NUM_ITERATIONS; ++i) {
oneIsThreaSafeTest();
}
}
public void oneIsThreadSafeTest() {
final int NUM_THREADS = 1000;
final int UNIT_ID = 1;
final Response_Unit_Manager manager = new Response_Unit_Manager();
ExecutorService exec = Executors.newFixedThreadPool(NUM_THREADS);
CountdownLatch allThreadsWaitOnThis = new CountdownLatch(1);
AtomicInteger numThreadsSawException = new AtomicInteger(0);
for (int i = 0; i < NUM_THREADS; ++i) {
// this is a Java 8 Lambda, if using Java 7 or less you'd use a
// class that implements Runnable
exec.submit(() -> {
allThreadsWaitOnThis.await();
// making some assumptions here about how you construct
// a Response_Unit
Response_Unit unit = new Response_Unit(UNIT_ID);
try {
manager.Add_Response_Unit(unit);
} catch (Duplicate_Item_Exception e) {
numThreadsSawException.incrementAndGet();
}
});
// release all the threads
allThreadsWaitOnThis.countdown();
// wait for them all to finish
exec.shutdown();
exec.awaitTermination(10, TimeUnits.MINUTES);
assertThat(numThreadsSawException.get()).isEqualTo(NUM_THREADS - 1);
}
You can construct similar tests for the other potential thread safety issues.
The easiest way to find errors with testing, like the one which is contained in your class, is to use a Testrunner like for example the following:
package com.anarsoft.mit;
import java.util.concurrent.atomic.AtomicInteger;
public class Test_Response_Unit_Manager implements Runnable {
private final AtomicInteger threadCount = new AtomicInteger();
public void test() throws Exception
{
for(int i = 0; i < 2 ;i++)
{
Thread thread = new Thread(this, "Thread " + i);
this.threadCount.incrementAndGet();
thread.start();
}
while( this.threadCount.get() > 0 )
{
Thread.sleep(1000);
}
Thread.sleep(10 * 1000);
}
public void run()
{
exec();
threadCount.decrementAndGet();
}
protected void exec()
{
Response_Unit_Manager.Add_Response_Unit(new Response_Unit(Thread.currentThread().getId()));
}
public static void main(String[] args) throws Exception
{
(new Test_Response_Unit_Manager()).test();
}
}
And to use a dynamic race condition detection tool like http://vmlens.com, a lightweight race condition detector. This will show you the following race conditions:
And the stacktraces leading to the bug. On the left the write and one the right the read.
http://vmlens.com works with eclipse, so it depens on the ide you are using, if its useful for you

why is this thread safe?

Because it always prints out '3'. No synchronization needed? I am testing this simple thing because I am having a trouble in a real multiple thread problem, which isn't good to illustrate the problem, because it's large. This is a simplified version to showcase the situation.
class Test {
public static int count = 0;
class CountThread extends Thread {
public void run()
{
count++;
}
}
public void add(){
CountThread a = new CountThread();
CountThread b = new CountThread();
CountThread c = new CountThread();
a.start();
b.start();
c.start();
try {
a.join();
b.join();
c.join();
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
public static void main(String[] args) {
Test test = new Test();
System.out.println("START = " + Test.count);
test.add();
System.out.println("END: Account balance = " + Test.count);
}
Because it always prints out '3'. No synchronization needed?
It is not thread safe and you are just getting lucky. If you run this 1000 times, or on different architectures, you will see different output -- i.e. not 3.
I would suggest using AtomicInteger instead of a static field ++ which is not synchronized.
public static AtomicInteger count = new AtomicInteger();
...
public void run() {
count.incrementAndGet();
}
...
Seems to me like count++ is fast enough to finish until you invoke 'run' for the other class. So basically it runs sequential.
But, if this was a real life example, and two different threads were usingCountThread parallelly, then yes, you would have synchronization problem.
To verify that, you can try to print some test output before count++ and after, then you'll see if b.start() is invoking count++ before a.start() finished. Same for c.start().
Consider using AtomicInteger instead, which is way better than synchronizing when possible -
incrementAndGet
public final int incrementAndGet()
Atomically increments by one the current value.
This code is not thread-safe:
public static int count = 0;
class CountThread extends Thread {
public void run()
{
count++;
}
}
You can run this code a million times on one system and it might pass every time. This does not mean is it is thread-safe.
Consider a system where the value in count is copied to multiple processor caches. They all might be updated independently before something forces one of the caches to be copied back to main RAM. Consider that ++ is not an atomic operation. The order of reading and writing of count may cause data to be lost.
The correct way to implement this code (using Java 5 and above):
public static java.util.concurrent.atomic.AtomicInteger count =
new java.util.concurrent.atomic.AtomicInteger();
class CountThread extends Thread {
public void run()
{
count.incrementAndGet();
}
}
It's not thread safe just because the output is right. Creating a thread causes a lot of overhead on the OS side of things, and after that it's just to be expected that that single line of code will be done within a single timeslice. It's not thread safe by any means, just not enough potential conflicts to actually trigger one.
It is not thread safe.
It just happened to be way to short to have measurable chance to show the issue. Consider counting to much higher number (1000000?) in run to increase chance of 2 operations on multiple threads to overlap.
Also make sure your machine is not single core CPU...
To make the class threadsafe either make count volatile to force memory fences between threads, or use AtomicInteger, or rewrite like this (my preference):
class CountThread extends Thread {
private static final Object lock = new Object();
public void run()
{
synchronized(lock) {
count++;
}
}
}

Should you synchronize the run method? Why or why not?

I have always thought that synchronizing the run method in a java class which implements Runnable is redundant. I am trying to figure out why people do this:
public class ThreadedClass implements Runnable{
//other stuff
public synchronized void run(){
while(true)
//do some stuff in a thread
}
}
}
It seems redundant and unnecessary since they are obtaining the object's lock for another thread. Or rather, they are making explicit that only one thread has access to the run() method. But since its the run method, isn't it itself its own thread? Therefore, only it can access itself and it doesn't need a separate locking mechanism?
I found a suggestion online that by synchronizing the run method you could potentially create a de-facto thread queue for instance by doing this:
public void createThreadQueue(){
ThreadedClass a = new ThreadedClass();
new Thread(a, "First one").start();
new Thread(a, "Second one, waiting on the first one").start();
new Thread(a, "Third one, waiting on the other two...").start();
}
I would never do that personally, but it lends to the question of why anyone would synchronize the run method. Any ideas why or why not one should synchronize the run method?
Synchronizing the run() method of a Runnable is completely pointless unless you want to share the Runnable among multiple threads and you want to sequentialize the execution of those threads. Which is basically a contradiction in terms.
There is in theory another much more complicated scenario in which you might want to synchronize the run() method, which again involves sharing the Runnable among multiple threads but also makes use of wait() and notify(). I've never encountered it in 21+ years of Java.
There is 1 advantage to using synchronized void blah() over void blah() { synchronized(this) { and that is your resulting bytecode will be 1 byte shorter, since the synchronization will be part of the method signature instead of an operation by itself. This may influence the chance to inline the method by the JIT compiler. Other than that there is no difference.
The best option is to use an internal private final Object lock = new Object() to prevent someone from potentially locking your monitor. It achieves the same result without the downside of the evil outside locking. You do have that extra byte, but it rarely makes a difference.
So I would say no, don't use the synchronized keyword in the signature. Instead, use something like
public class ThreadedClass implements Runnable{
private final Object lock = new Object();
public void run(){
synchronized(lock) {
while(true)
//do some stuff in a thread
}
}
}
}
Edit in response to comment:
Consider what synchronization does: it prevents other threads from entering the same code block. So imagine you have a class like the one below. Let's say the current size is 10. Someone tries to perform an add and it forces a resize of the backing array. While they're in the middle of resizing the array, someone calls a makeExactSize(5) on a different thread. Now all of a sudden you're trying to access data[6] and it bombs out on you. Synchronization is supposed to prevent that from happening. In multithreaded programs you simply NEED synchronization.
class Stack {
int[] data = new int[10];
int pos = 0;
void add(int inc) {
if(pos == data.length) {
int[] tmp = new int[pos*2];
for(int i = 0; i < pos; i++) tmp[i] = data[i];
data = tmp;
}
data[pos++] = inc;
}
int remove() {
return data[pos--];
}
void makeExactSize(int size) {
int[] tmp = new int[size];
for(int i = 0; i < size; i++) tmp[i] = data[i];
data = tmp;
}
}
Why? Minimal extra safety and I don't see any plausible scenario where it would make a difference.
Why not? It's not standard. If you are coding as part of a team, when some other member sees your synchronized run he'll probably waste 30 minutes trying to figure out what is so special either with your run or with the framework you are using to run the Runnable's.
From my experience, it's not useful to add "synchronized" keyword to run() method. If we need synchronize multiple threads, or we need a thread-safe queue, we can use more appropriate components, such as ConcurrentLinkedQueue.
Well you could theoretically call the run method itself without problem (after all it is public). But that doesn't mean one should do it. So basically there's no reason to do this, apart from adding negligible overhead to the thread calling run(). Well except if you use the instance multiple times calling new Thread - although I'm a) not sure that's legal with the threading API and b) seems completely useless.
Also your createThreadQueue doesn't work. synchronized on a non-static method synchronizes on the instance object (ie this), so all three threads will run in parallel.
Go through the code comments and uncomment and run the different blocks to clearly see the difference, note synchronization will have a difference only if the same runnable instance is used, if each thread started gets a new runnable it won't make any difference.
class Kat{
public static void main(String... args){
Thread t1;
// MyUsualRunnable is usual stuff, only this will allow concurrency
MyUsualRunnable m0 = new MyUsualRunnable();
for(int i = 0; i < 5; i++){
t1 = new Thread(m0);//*imp* here all threads created are passed the same runnable instance
t1.start();
}
// run() method is synchronized , concurrency killed
// uncomment below block and run to see the difference
MySynchRunnable1 m1 = new MySynchRunnable1();
for(int i = 0; i < 5; i++){
t1 = new Thread(m1);//*imp* here all threads created are passed the same runnable instance, m1
// if new insances of runnable above were created for each loop then synchronizing will have no effect
t1.start();
}
// run() method has synchronized block which lock on runnable instance , concurrency killed
// uncomment below block and run to see the difference
/*
MySynchRunnable2 m2 = new MySynchRunnable2();
for(int i = 0; i < 5; i++){
// if new insances of runnable above were created for each loop then synchronizing will have no effect
t1 = new Thread(m2);//*imp* here all threads created are passed the same runnable instance, m2
t1.start();
}*/
}
}
class MyUsualRunnable implements Runnable{
#Override
public void run(){
try {Thread.sleep(1000);} catch (InterruptedException e) {}
}
}
class MySynchRunnable1 implements Runnable{
// this is implicit synchronization
//on the runnable instance as the run()
// method is synchronized
#Override
public synchronized void run(){
try {Thread.sleep(1000);} catch (InterruptedException e) {}
}
}
class MySynchRunnable2 implements Runnable{
// this is explicit synchronization
//on the runnable instance
//inside the synchronized block
// MySynchRunnable2 is totally equivalent to MySynchRunnable1
// usually we never synchronize on this or synchronize the run() method
#Override
public void run(){
synchronized(this){
try {Thread.sleep(1000);} catch (InterruptedException e) {}
}
}
}

Categories

Resources