"trivia"? "Lock things up".

Hello everyone, I have 方圆
checked the missing knowledge and made up the missing knowledge.


1. synchronized

It will happen when an exception occurs自动释放锁


2. Did you know that Git is optimistic locking?

When we push to the remote warehouse, git will check whether the version of the remote warehouse is higher than ours now 版本. If it is, it means that someone has modified the remote code and we cannot submit it, and need to synchronize first. ; If they are 版本consistent, the submission can be successful

2.1 Implement optimistic locking in MySQL

We need to create a separate versioncolumn to mark the version number so that every time we modify the data, the version number will be verified

Insert picture description here

The SQL statement is as follows

UPDATE active SET num = 3 ,`version` = `version` + 1 WHERE id = 1 AND `version` = 1

2.2 Applicable scenarios of optimistic locking

Optimistic lock: suitable for 读多 写少scenarios where no lock can greatly improve efficiency.
Pessimistic lock: suitable 大并发, 代码复杂or循环量大


3. Fair lock and unfair lock

  • Fair lock: 不允许插队Yes, whoever comes first will get the lock first
  • Unfair lock: 允许插队Yes, this is possible 提高效率, 避免了唤醒带来的空档期and it is also the default strategy of ReentrantLock

3.1 Come and see this special case

  • There is one of ReentrantLock tryLock方法, which is really powerful. It does not 不遵守我们既定的公平策略, how can I say, that once a thread releases the locked resource, then this 执行了tryLock方法的线程就能获取到锁, even if there is already a thread queued in the front, it is just like a VIP

4. Queue jump strategy for read-write lock

  • Fair lock: no jump in line is allowed
  • Unfair lock: 写锁You can jump 读锁in the queue at any time; you can jump in the queue only when the head node of 想要获取读锁the blocking queue is the thread that you want to acquire; when the node in the blocking queue is the thread that you want to acquire 写锁, then 不能进行插队this can happen 避免发生饥饿(starvation means acquiring the write lock is always Jump in the queue and never get the lock)
    Insert picture description here

4.1 Code test

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReadAndWriteDemo2 {
    
    
    private static final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock(true);
    private static ReentrantReadWriteLock.ReadLock readLock = readWriteLock.readLock();
    private static ReentrantReadWriteLock.WriteLock writeLock = readWriteLock.writeLock();

    public static void read() {
    
    
        System.out.println(Thread.currentThread().getName() + "尝试获取读锁");
        readLock.lock();
        try {
    
    
            System.out.println(Thread.currentThread().getName() + "获取到了读锁");
            TimeUnit.MILLISECONDS.sleep(80);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            readLock.unlock();
        }
    }

    public static void write() {
    
    
        System.out.println(Thread.currentThread().getName() + "尝试获取写锁");
        writeLock.lock();
        try {
    
    
            System.out.println(Thread.currentThread().getName() + "获取到了写锁");
            TimeUnit.MILLISECONDS.sleep(100);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            writeLock.unlock();
            System.out.println(Thread.currentThread().getName() + "释放了写锁");
        }
    }

    public static void main(String[] args) {
    
    
        new Thread(() -> write(),"A").start();
        new Thread(() -> read(),"B").start();
        new Thread(() -> read(),"C").start();
        new Thread(() -> {
    
    
            for (int i = 0; i < 1500; i++) {
    
    
                new Thread(() -> read(),String.valueOf(i)).start();
            }
        }).start();
    }
}
  • In 非公平the case of ↓
    Insert picture description here
  • In 公平the case of ↓
    Insert picture description here

5. Write a deadlock

5.1 Code

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

public class DeadLockDemo2 {
    
    
    public static void main(String[] args) throws InterruptedException {
    
    
        DeadLock deadLock = new DeadLock(1);
        new Thread(deadLock,"1").start();
        TimeUnit.MILLISECONDS.sleep(1);
        deadLock.setFlag(2);
        new Thread(deadLock,"2").start();
    }
}

class DeadLock implements Runnable{
    
    

    private ReentrantLock lock1 = new ReentrantLock();
    private ReentrantLock lock2 = new ReentrantLock();
    private int flag;

    public DeadLock(int flag) {
    
    
        this.flag = flag;
    }

    public void setFlag(int flag) {
    
    
        this.flag = flag;
    }

    //TODO tryLock避免死锁式,注意tryLock方法的使用位置,是在if条件中
    @Override
    public void run() {
    
    
        if(flag == 1) {
    
    
            if(lock1.tryLock()) {
    
    
                try {
    
    
                    System.out.println(Thread.currentThread().getName() + "成功获取到了锁1");
                    TimeUnit.SECONDS.sleep(1);
                    if(lock2.tryLock()) {
    
    
                        try {
    
    
                            System.out.println(Thread.currentThread().getName() + "成功获取到了锁2");
                        }finally {
    
    
                            lock2.unlock();
                        }
                    }else {
    
    
                        System.out.println(Thread.currentThread().getName() + "获取锁2失败");
                    }
                } catch (InterruptedException e) {
    
    
                    e.printStackTrace();
                }finally {
    
    
                    lock1.unlock();
                }
            }else {
    
    
                System.out.println(Thread.currentThread().getName() + "获取锁1失败");
            }
        }else {
    
    
            if(lock2.tryLock()) {
    
    
                try {
    
    
                    System.out.println(Thread.currentThread().getName() + "成功获取到了锁2");
                    TimeUnit.SECONDS.sleep(1);
                    if(lock1.tryLock()) {
    
    
                        try {
    
    
                            System.out.println(Thread.currentThread().getName() + "成功获取到了锁1");
                        }finally {
    
    
                            lock1.unlock();
                        }
                    }else {
    
    
                        System.out.println(Thread.currentThread().getName() + "获取锁1失败");
                    }
                } catch (InterruptedException e) {
    
    
                    e.printStackTrace();
                }finally {
    
    
                    lock2.unlock();
                }
            }else {
    
    
                System.out.println(Thread.currentThread().getName() + "获取锁2失败");
            }
        }
    }

    //TODO 死锁式
    /*@Override
    public void run() {
        if(flag == 1) {
            lock1.lock();
            try {
                System.out.println(Thread.currentThread().getName() + "获取到了锁1");
                TimeUnit.SECONDS.sleep(1);
                System.out.println(Thread.currentThread().getName() + "尝试获取锁2");
                lock2.lock();
                try {
                    System.out.println(Thread.currentThread().getName() + "获取到了锁2");
                }finally {
                    lock2.unlock();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock1.unlock();
            }
        }else {
            lock2.lock();
            try {
                System.out.println(Thread.currentThread().getName() + "获取到了锁2");
                TimeUnit.SECONDS.sleep(1);
                System.out.println(Thread.currentThread().getName() + "尝试获取锁1");
                lock1.lock();
                try {
                    System.out.println(Thread.currentThread().getName() + "获取到了锁1");
                }finally {
                    lock1.unlock();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock2.unlock();
            }
        }
    }*/
}

5.2 Summary

In the above code, two methods are provided. One is 死锁the situation that will occur , which is called lock方法; the other is 不会发生死锁the situation, that is, when it is used tryLock方法, this method can try to acquire the lock, and it will automatically give up if the lock is not acquired. Of course we You can also specify the waiting time. At the same time, we must pay attention to the use position of tryLock. It is in the if条件语句middle , which is somewhat different from the lock method.

If a deadlock occurs, we have a solution,

usejps -lThe command displays the information of the process, what we want is the process number, and
then according to the process number we usejstack process ID We can view the stack informationInsert picture description here


6. Spin lock

Spin lock: Blocking or waking up a Java thread requires the CPU to switch state to complete, which takes time. If our code is too simple, 切换状态消耗的时间可能会比用户代码执行的时间还要长in order to avoid this situation, a spin lock is born as needed, and it will let the thread Perform continuous spin until the lock is acquired, avoiding the overhead of changing threads first (but the JVM will optimize the spin lock, there is a threshold for the number of spins, after which it will stop spinning)
atomic包. The above are all implementations of spin locks, such as AtomicInteger. Its principle is CAS. Its getAndIncrement方法(increment) is the spin lock used. Called Unsafe的getAndAddInt方法as follows, it stops until the modification is successful.

Insert picture description here

  • Limitations:
    If the spin lock is occupied for too long, then the spinning thread will only waste processor resources in vain

  • Applicable scenarios
    When the concurrency is not particularly high, and the code block is relatively simple

6.1 Handwriting a simple spin lock

public class SpinLockDemo {
    
    
    private AtomicReference<Thread> spinLock = new AtomicReference<>();
    
    public void lock() {
    
    
        Thread cur = Thread.currentThread();
        
        while(spinLock.compareAndSet(null,cur)) {
    
    
            
        }
    }
    
    public void unLock() {
    
    
        Thread cur = Thread.currentThread();
        spinLock.compareAndSet(cur,null);
    }
}

Come on!

Guess you like

Origin blog.csdn.net/qq_46225886/article/details/108038072