• Why do we have thread locks?

Multiple threads will rob resources, so it is possible that one thread will be robbed of resources in the middle of execution by another thread, which will cause thread insecurity. In order to ensure thread security, we can use thread lock to solve this problem.

For example, in the following example, it is normal to print out two sentences, “Did you study today? However, it is possible that thread1 is halfway through its execution when Thread2 steals resources, thus causing the execution order to be out of order:

public class ThreadDemo {

    public static void main(String[] args) throws InterruptedException {
        MyThread myThread1 = new MyThread();
        MyThread myThread2 = new MyThread();

        myThread1.start();
        myThread2.start();
    }

    static class MyThread extends Thread {
        @Override
        public void run(a) {
            for (char c : "Did you study today?".toCharArray()) { System.out.print(c); }}}} Execution result: Today you learn today you learn? Xi?// The order is out of order ❌
Copy the code
  • How to solve thread insecurity?

The example above causes thread insecurity, which we can use synchronized to solve:

public class ThreadDemo {

    public static void main(String[] args) throws InterruptedException {
        MyThread myThread1 = new MyThread();
        MyThread myThread2 = new MyThread();

        myThread1.start();
        myThread2.start();
    }

    static class MyThread extends Thread {
        @Override
        public void run(a) {
            // Lock ✅ here
            synchronized (ThreadDemo.class){
                for (char c : "Did you study today?".toCharArray()) { System.out.print(c); }}}}} Execution result: did you study today? Did you study today?// Correct order ✅
Copy the code
  • Synchronized,

To solve the thread-safety problem, we only need to add synchronized, which is also referred to as “synchronized”.Synchronization lock“Synchronized” is a keyword,Member methods can be decorated or written separately as synchronized blocks of code, synchronized code block,At most one thread can execute at a timeCode in a code block.

Can be seen in the figure above, in order to prevent multiple threads to modify the code at the same time affect the safety of the code, we use the lock will be part of the code lock up, to seize the lock between multiple threads, and only one thread can get a lock for execute permissions, other threads can only wait outside the thread lock is released, then again rob execute permissions. This solves the problem of thread insecurity.

  • Object lock

Methods aprivate synchronized void count(a){... } method 2private void count(a){
    synchronized (this) {... }} Method 3private Object mObject = new Object();

private void count(a){
    synchronized(mObject){ ... }}Copy the code
  • Kind of lock

Methods aprivate synchronized static void count(a){... } method 2private static void count(a){
    synchronized(ThreadDemo.class){ ... }} Method 3private static Object mObject = new Object();

private void count(a){
    synchronized(mObject){ ... }}Copy the code
  • conclusion

Object lock: The object lock is an instance of an object. When multiple threads use the object, they need to ensure that the same instance is used. Otherwise, the lock is meaningless.

Class lock: A class lock locks the only class object of a class. Static methods plus synchronized are class locks by default.

Note: Class locks and object locks can be used together without interfering with each other.

  • Wait () and notify() and notifyAll()

Wait (): When a thread executes the wait() method, it releases the lock, releases the CPU, and waits until it is awakened by the notify()/notifyAll().

Notify (): Wakes up a thread in the WAIT state.

NotifyAll (): wakes up all threads in the WAIT state.

  • The two threads print 0 to 100 alternately

This is easily implemented using wait(), notify(), and synchronized:

public class ThreadDemo {

    private static int num;
    private static Object sObject = new Object();

    public static void main(String[] args) {
        new Thread(new MyRunnable(),Thread 1 "").start();
        new Thread(new MyRunnable(),Thread 2 "").start();
    }

    static class MyRunnable implements Runnable {
        @Override
        public void run(a) {
            while (true) {
                synchronized (sObject){
                    System.out.println(Thread.currentThread().getName() + ":"+ num++);
                    sObject.notify();
                    if (num>=100) return;
                    try {
                        sObject.wait();
                    } catch(InterruptedException e) { e.printStackTrace(); }}}}}} Print: thread1: 0thread2: 1thread1: 2. thread2: 99thread1: 100
Copy the code