简体   繁体   中英

Are private variables thread safe

Does a developer who is developing an api (like Collections api in java) should manually throw ConcurrentModificationException when two threads try to modify the object's data?

Why does this piece of code not throw an exception as multiple threads try to modify the content of the Person 's object?

public class Main {

    public static void main(String[] args) {
    // write your code here
        RunnableDemo r = new RunnableDemo();
        for (int i = 0; i < 10; i++) {
            Thread t = new Thread(r, "Thread " + i);
            t.start();
        }
    }
}

class RunnableDemo implements Runnable {

    private Person person = new Person();

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            person.setName("Person" + i);
            System.out.println(person.getName());
        }
    }
}

class Person {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

You should throw an exception when you think that you have to. your code does not throw an exception when two threads try to modify the person object concurrently but you may get unpredictable results in such a situation and you should prevent concurrent modification manually.

If you want your class to throw ConcurrentModificationException , then you will have to write the code that throws it.


Java doesn't throw ConcurrentModficationException because of two threads trying to update the same object at the same time. In fact, Java never throws ConcurrentModificationException.

Some standard Java library classes throw that exception when they notice that an object is in a bad state that only could have been caused by the caller breaking the rules.

For example, The Javadoc for some container classes says that you are not allowed to modify the container while you are iterating over it. If your code gets an iterator, then updates the container, and then calls iterator.next() , the next() call will throw ConcurrentModificationException when it notices that the container is no longer in the same state as when the iterator was created.

The throw in that case is explicit. It doesn't come out of the heart of Java: It's in the source code for the container class. If you look at the source code for the class, you'll see something like:

    public T next() {
        if (...the container has been modified...) {
            throw new ConcurrentModificationException(...);
        }
        ...
    }

If you want your class to throw that exception, then you'll have to write some similar code.

Let us understand this one step at time.
For starters, I will try answering few questions that may have crossed your mind.

a) Are you creating multiple threads?
Ans . Yes for sure, you are creating 101 logical threads (1 main thread + 100 other by calling start() method of thread) . By logical I mean is that there are not actual 100 parallel threads, instead they are mapped to the core kernel threads (basically the number of cores).

Each core has a work queue and the logical threads gets assigned to the cores. It may so happen (lets say in a dual core machine) that one of the core is so busy in processing some task that all the application threads (created by your program) gets mapped to the same core.

It is the decision of JVM how to map the threads and to schedule the logical threads and its execution time as well.

b) What happens when you call start()?
Ans. A good and precise overview on the life cycle of the thread is available at: http://www.javatpoint.com/life-cycle-of-a-thread .

To highlight, calling start() method does not entitle a thread to be in the running state. It has to be picked up by the Thread scheduler to get into that state. Hence not all threads started by the program may be actually running in parallel.

c) So what has happened here having said that?
Ans. In your case, the task is so small that JVM decides to let go of one thread before scheduling another thread. Because according to JVM, if it does not do so, lot of time will be wasted in acquiring and releasing CPU resources and hence a lot of time will be wasted in context switching.

There goes your general explanation.

- What are you understanding wrong here?
Ans. To get an exception, some one must have to throw an exception first. The entire code does nothing to generate an exception.

You are setting "name" to a new reference with every thread and not modifying the state of the String (which actually are immutable in JAVA).

Does a developer who is developing an api (like Collections api in java) should manually throw ConcurrentModificationException when two threads try to modify the object's data?
Ans. An API which is not entitled to be thread safe should throw ConcurrentModificationException if the state can be modified by multiple threads and can impact the user seeing the corresponding state of the data structure (like ArrayList, HashMap etc.)

/*
 * Thread-Safe Example in Java
 */
public class Counter {

    private int count;
    AtomicInteger atomicCount = new AtomicInteger( 0 );


    /*
     * This method thread-safe now because of locking and synchornization
     */
    public synchronized int getCount(){
        return count++;
    }

    /*
     * This method is thread-safe because count is incremented atomically
     */
    public int getCountAtomically(){
        return atomicCount.incrementAndGet();
    }
}

Read more: http://javarevisited.blogspot.com/2012/01/how-to-write-thread-safe-code-in-java.html#ixzz4z8Rx4P2Y

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM