简体   繁体   中英

Do multiple threads Using the same object in java make a copy of it?

How do multiple threads in Java handle working with a single object reference passed to them?

Do they make a copy of the object and then use it, or do they use the same one?

Any technical explanation is welcome.

I am unable to comprehend this in the context that if the threads pass some data to the object and go to sleep, while one is asleep another thread uses the same object passes data to it and goes to sleep.

Will the last data overwrite the previous one in the object?

Do they make a copy of the object and then use it, or do they use the same one?

Both, actually.

Modern computers are designed according to Symmetric Multiprocessor Architecture (SMP) , in which several CPUs compete for access a common memory system. In order to reduce the amount of competition, each processor has its own cache -- a small amount of higher-speed memory -- where it keeps working copies of data that belong in main memory.

Cacheing happens in the hardware, and the hardware knows nothing about Java objects, so it happens on a byte-by-byte level, not on an object-by-object level.

At the language level, there is only one copy of an object, but at the hardware level, different threads running on different processors can have their own copies of parts of the object.


The topic of how different threads running on processors can agree on what some object actually is supposed to look like is called cache coordination.

Java has strict rules about when and how different threads must coordinate their caches. To learn more about those rules, Google for "Java" and "memory model", or "memory visibility", or "happens before."


If you don't want to read all of the gory details, the secret is in judicious use of synchronized blocks and synchronized methods. If you only want to remember one rule, remember this: Whatever one thread does to shared objects before it leaves a synchronized block is guaranteed to become visible to other threads after those threads enter a block that is synchronized on the same lock.

Do they make a copy of the object and then use it?

No. They all use the same object.

However, the memory system design of a typical modern computer means that some of the state of an object may be held in machine registers and memory caches associated with more than one processor in a multi-processor system.

Proper synchronization is therefore necessary for shared mutable objects for two reasons:

  • to avoid race conditions caused by two threads trying to read / modify the object at the same time, and
  • to avoid memory hazards caused by one thread not seeing variable updates made by another thread due to caching (see above).

Any technical explanation is welcome.

This is no different to how objects are passed in single-threaded contexts. References to objects are passed by value. No copying of objects. Only copying of references.

Will the last data overwrite the previous one in the object?

If you implement the synchronization correctly, then yes. If you don't then this is not guaranteed. Indeed, it is possible for one thread to never see the updates made to a shared object ... if you don't implement the synchronization correctly.

In fact, there is a section of the Java Language Specification that defines the Java Memory Model. This specifies what you need to do in your program to ensure that memory changes made by one thread will always be visible to another thread.

You can look at java memory model. You see all objects are stored in Heap memory, which is shared across whole application. Every thread shares the same heap space, but also they have own stack memory where they store their reference to the objects. So if one threads works on object, it have his own reference to this object, but this reference is pointing to the object in heap space, which every thread will see. So to answer to your question, if second thread will do something on the object, and then go to sleep or even die, the previous thread while wake up will see those changes, because its reference is pointing to same object.

I've found interesting image which can help you understand:

http://tutorials.jenkov.com/java-concurrency/java-memory-model.html

image from: http://tutorials.jenkov.com/java-concurrency/java-memory-model.html

Do they make a copy of the object and then use it or do they use the same one

No copy is done. Threads will use same object.

From a personal example. I was making a space invaders game for personal growing and it used multiple Thread s. One Thread handled the rendering and another handled game logic. This is before I had a firm grasp on concurrency and how to properly implement it in Java.

Anyways, I had an ArrayList<Laser> that held all of the Laser s in the system at any given frame in the game (or so I thought). Because of the nature of space invaders, that List was extremely dynamic. It was constantly being added to as new Laser s spawned and removed from as they either went off the map or collided with an entity.

This worked all well and good, except every so often I would receive a ConcurrentModificationException . It took me a long time to figure out exactly what was going on. It turns out that the rendering Thread was on rare occasions being caught iterating through the List<Laser> at the same time as the game logic Thread was either adding new Laser s or removing them.

This is because when Thread 1 gets the pointer to the List objects spot in memory, it's almost as though it is in the process of "operating" on that memory block. Thread 2 comes along and grabs that same pointer unaware that the object is already on the "operating table" being modified by Thread 1 and it tries to go about doing what it intended, only to find that what Thread 2 thought it really knew about the object was incorrect due to Thread 1's modifications. This is what ends up throwing the ConcurrentModificationException .

This can be solved several different ways. I think the most efficient and safe way to solve this now is with Java 8's Stream API (If done properly, it will ensure true parallelism), or you can use synchronized blocks (I think they came into existence in Java 5). With synchronized blocks, the current Thread that is looking at the object will essentially lock it, not allowing any other Thread s to even observe the object. Once the Thread is done, it releases the object for the next Thread to operate on it.

Here is two examples of how to use synchronized :

public synchronized void xamp1(List<Laser> lasers){
    for(Laser l:lasers){
        //code to observe or modify
    }
}


public void xamp2(List<Laser> lasers){
   synchronized(lasers){
        for(Laser l:lasers){
             //code to observe or modify
        }
   }
}

Threads could make copies, if:

  1. you write the code to that
  2. the incoming objects can actually be "copied" (cloned that is)

In other words: the default is that there is no implicit copying whatsoever. Not with 1 thread; not with N threads involved.

If you need such functionality, you have implement yourself.

For simple situations, like passing a list; that can be done pretty easily (for the top level):

List<Whatever> duplicatedList = new ArrayList<>(existingList);

to then give duplicatedList to other threads. But of course: this only creates multiple lists - the list entries are still referencing the very same objects!

Deep cloning is a concept that is hard to do in java, and thus rarely used in practice.

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