Talk about the understanding of java thread (three) -------- keyword synchronized

Speaking of the keyword synchronized, I think everyone is familiar with it. Maybe you rarely use this keyword in your code. After all, the singleton mode has been encapsulated. If there is a problem of multi-threaded concurrency, you generally use distributed locks, because the preemption of resources is all For databases or other shared resources, and the current deployment is distributed, so the role of synchronized in the usual code appears to be much less.

However, everyone will often see this field. For example, we know that ArrayList is thread-unsafe. Why is Vector thread-safe? Oh, it turns out that a synchronized lock is added to prevent concurrent additions and deletions. HashMap is thread-unsafe. When concurrent and hash collision occurs, it is almost equivalent to operating a linkedList, and there may be problems when adding it. Why is ConcurrentHashMap thread-safe? Oh, it turns out that the CAS operation and the use of synchronized lock slots are used to refine the granular lock , While avoiding the possible problems of HashMap.

Okay, let's take a look at the keyword synchronized together.

Synchronized generally means locking methods, static methods, and code blocks. In some places, it is said that it will lock classes. In fact, there are two types in general, class-level locks and method-level locks. Let's look at the code:

1. Lock synchronization code blocks and lock objects.

public class SyncThread implements Runnable {

    private Integer number = 0;

    public void method() throws Exception{
        synchronized (this) {
            for (int i = 0; i < 5; i++) {
                System.out.println(Thread.currentThread().getName()+"-synchronized锁同步代码块:"+number++);
                Thread.sleep(10);
            }
        }

    }

    @Override
    public void run() {
        try {
            method();
        } catch (Exception e) {

        }
    }
}

Let's run it

    public static void main(String[] args) {

        SyncThread syncThread = new SyncThread();
         Thread thread1 = new Thread(syncThread, "SyncThread1");
         Thread thread2 = new Thread(syncThread, "SyncThread2");
         thread1.start();
         thread2.start();
    }

We created a SyncThread object, and then created two threads through SyncThread, and then started, which means that both threads will operate the same number, of course, the first one will be locked, and then the execution is completed, the next thread continues to execute , Then the result is:

SyncThread1-synchronized锁同步代码块:0
SyncThread1-synchronized锁同步代码块:1
SyncThread1-synchronized锁同步代码块:2
SyncThread1-synchronized锁同步代码块:3
SyncThread1-synchronized锁同步代码块:4
SyncThread2-synchronized锁同步代码块:5
SyncThread2-synchronized锁同步代码块:6
SyncThread2-synchronized锁同步代码块:7
SyncThread2-synchronized锁同步代码块:8
SyncThread2-synchronized锁同步代码块:9

Some partners will be surprised. Why don't thread one thread two alternate execution and accumulation? They operate the same method to implement runnable, which is equivalent to a thread blocking in synchronized after entering the method. Where does the alternate execution come from?

Of course, if you want to perform alternately, you can just create two SyncThread.


         Thread thread1 = new Thread(new SyncThread(), "SyncThread1");
         Thread thread2 = new Thread(new SyncThread(), "SyncThread2");
         thread1.start();
         thread2.start();

Once running, clang. .

SyncThread1-synchronized锁同步代码块:0
SyncThread2-synchronized锁同步代码块:0
SyncThread2-synchronized锁同步代码块:1
SyncThread1-synchronized锁同步代码块:1
SyncThread2-synchronized锁同步代码块:2
SyncThread1-synchronized锁同步代码块:2
SyncThread2-synchronized锁同步代码块:3
SyncThread1-synchronized锁同步代码块:3
SyncThread2-synchronized锁同步代码块:4
SyncThread1-synchronized锁同步代码块:4

I found that Thread 1 and Thread 2 are doing their own things. Are they originally two classes? The locks are methods, and variables are ordinary variables. There is no competition between the two objects. Note that they are objects. So how do you make them competitive? That is to upgrade the lock to a class lock. The simplest method is number plus static, which is equivalent to binding to an object. All classes operate on this number. Of course, at this time, if we continue to just do code blocks, there will definitely be concurrent questions. The lock must rise to class locks or static object locks. Let's look at the code:

 private static Integer number = 0;

    public void method() throws Exception{
        synchronized (number) {
            for (int i = 0; i < 5; i++) {
                System.out.println(Thread.currentThread().getName()+"-synchronized锁同步代码块:"+number++);
                Thread.sleep(10);
            }
        }

    }

Then run the kind of test method for two objects:

SyncThread1-synchronized锁同步代码块:0
SyncThread2-synchronized锁同步代码块:1
SyncThread2-synchronized锁同步代码块:2
SyncThread1-synchronized锁同步代码块:3
SyncThread2-synchronized锁同步代码块:4
SyncThread1-synchronized锁同步代码块:5
SyncThread2-synchronized锁同步代码块:6
SyncThread2-synchronized锁同步代码块:7
SyncThread1-synchronized锁同步代码块:8
SyncThread1-synchronized锁同步代码块:9

Process finished with exit code 0

If it is still synchronized (this), there will be concurrency problems, so you can try it yourself.

2. Locking method

    public synchronized void method() throws Exception {
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName() + "-synchronized锁同步代码块:" + number++);
            Thread.sleep(10);
        }
    }

Let's look at the results of the operation:

SyncThread1-synchronized锁同步代码块:0
SyncThread2-synchronized锁同步代码块:1
SyncThread2-synchronized锁同步代码块:2
SyncThread1-synchronized锁同步代码块:2
SyncThread1-synchronized锁同步代码块:3
SyncThread2-synchronized锁同步代码块:4
SyncThread1-synchronized锁同步代码块:5
SyncThread2-synchronized锁同步代码块:6
SyncThread1-synchronized锁同步代码块:7
SyncThread2-synchronized锁同步代码块:8

Process finished with exit code 0

At this time, you can see that the lock method and the lock synchronization code block are actually at the same level. They both lock the loop in the method and jointly seize the resource number.

What about static methods?

    public static synchronized void method() throws Exception {
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName() + "-synchronized锁同步代码块:" + number++);
            Thread.sleep(10);
        }
    }

Static methods are obviously class-level locks. You can see the results of the operation:

SyncThread1-synchronized锁同步代码块:0
SyncThread1-synchronized锁同步代码块:1
SyncThread1-synchronized锁同步代码块:2
SyncThread1-synchronized锁同步代码块:3
SyncThread1-synchronized锁同步代码块:4
SyncThread2-synchronized锁同步代码块:5
SyncThread2-synchronized锁同步代码块:6
SyncThread2-synchronized锁同步代码块:7
SyncThread2-synchronized锁同步代码块:8
SyncThread2-synchronized锁同步代码块:9

Process finished with exit code 0

Once the thread occupies the resource, the thread will wait for the completion of this method before releasing the resource. In fact, it is this class that is locked.

Of course, this is also an effect.


    public synchronized void method() throws Exception {
        synchronized (SyncThread.class) {
            for (int i = 0; i < 5; i++) {
                System.out.println(Thread.currentThread().getName() + "-synchronized锁同步代码块:" + number++);
                Thread.sleep(10);
            }
        }
    }

Well, we have roughly understood the synchronized lock, so how does synchronized realize the lock mechanism?

We all know that objects are created in the heap. And the storage layout of the object in the memory can be divided into three areas: object header, instance data, and alignment padding. Among them, the object header contains lock information. The following is the running data of the object header itself.

Store content Flag bit status
The hash code of the object, the generation age of the object 01 Not locked
Pointer to the lock record 00 Lightweight lock
Pointer to heavyweight lock 10 Heavyweight lock
air 11 GC mark
Thread ID bias, timestamp bias, generation age 01 Can be biased

 

Of course, there is also a type pointer, and the JVM uses this pointer to determine which class instance the object is.

Synchronized lock is actually a mixed lock of optimism and pessimism. The optimistic lock is processed first. If it fails, the pessimistic lock is used. The pessimistic lock, that is, the heavyweight lock, is implemented through the monitor. Synchronized object lock, its pointer points to the address of a monitor object, each object will have a monitor, where the monitor can be created and destroyed together with the object, or it can be automatically generated when the thread tries to acquire the lock. The monitor is implemented by C++. Those who are interested can explore it. I won't talk about it here.

We compile and view the method of locking the synchronization code block above (javap). We can see that monitorenter and monitorexit are actually locking and releasing the lock. When executing the monitorenter instruction, we must first try to acquire the object lock, that is, the monitor object. If the object is not locked, or the current thread already has the lock of this object, then we will increase the value of the lock by 1 (so the synchronized is OK Reentrant), of course, the monitor will be reduced by 1 when it is released.

Okay, that’s all about synchronized, there is something wrong there, you can point it out in the comments, it is very grateful!

 

No sacrifice,no victory !

Guess you like

Origin blog.csdn.net/zsah2011/article/details/107946415