Thread synchronization + lock

meaning

When dealing with multithreading, multiple threads access the same object, and some threads also want to modify the object. After that, we need thread synchronization. Thread synchronization is actually a waiting mechanism. Multiple threads that need to access the object at the same time enter the waiting pool of the object to form a queue, wait for the previous thread to use it, and then use it again for the next thread.

Forming condition: queue + lock

Lock (synchronized implicit lock)

Because multiple threads of the same process share the same storage space, it brings convenience and access conflict. In order to ensure the correctness of data access in the method, the lock mechanism synchronized is added during access. At present, one thread obtains the exclusive lock of the object and monopolizes resources. Other threads must wait and release the lock after use.

Problems:
1. A thread holding a lock will cause other threads that need the lock to hang;
2. In multi-threaded competition, locking and releasing locks will lead to more context switching and scheduling delays, resulting in performance problems.
3. If a thread with high priority waits for a thread with low priority to release the lock, it will cause priority inversion and performance problems

Unsafe thread test

package com.Thread;
//Unsafe thread test
public class UnSafeTest {
    public static void main(String[] args) {
    //account
        Account account=new Account(100,"Marriage fund");
        Drawing you =new Drawing(account,50,"you");
        Drawing me =new Drawing(account,100,"I");
        you.start();
        me.start();
    }
}
//account
class Account{
    int money;
    String name;

    public Account(int money, String name) {
        this.money = money;
        this.name = name;
    }
}
//Bank: simulated withdrawal
class Drawing extends Thread{
    Account account;//account
    //How much did you withdraw
    int drawingMoney;
    //How much money do you have now
   int nowMoney;
    public Drawing(Account account, int drawingMoney, String name) {
        super(name);

        this.account = account;
        this.drawingMoney = drawingMoney;

    }

    @Override
    public void run() {
       if(account.money-drawingMoney<0){
           System.out.println(Thread.currentThread().getName()+"There's not enough money to withdraw");
           return;
       }
       //sleep can amplify the occurrence of problems
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //Card balance
        account.money=account.money-drawingMoney;
        //The money in your hand
        nowMoney=nowMoney+drawingMoney;
        System.out.println(account.name+"The balance is"+account.money);
        System.out.println(this.getName()+"Money in hand"+nowMoney);
    }
}

Synchronization method

Because we can use the private keyword to ensure that data objects can only be accessed by methods, we only need to propose a mechanism for methods. This mechanism is the synchronized keyword, which includes two uses: the synchronized method and the synchronized block
Synchronized methods control access to "objects". Each object has a lock. Each synchronized method must obtain the lock of the object calling the method before it can be executed. Otherwise, the thread will block. Once the method is executed, it will monopolize the lock until the method returns. The blocked thread can obtain the lock and continue to execute
**Defect: * * declaring a large method synchronized will affect efficiency

Synchronization block


Synchronous thread test:

package com.Thread;
//Unsafe thread test
public class UnSafeTest {
    public static void main(String[] args) {
    //account
        Account account=new Account(100,"Marriage fund");
        Drawing you =new Drawing(account,50,"you");
        Drawing me =new Drawing(account,100,"I");
        you.start();
        me.start();
    }
}
//account
class Account{
    int money;
    String name;

    public Account(int money, String name) {
        this.money = money;
        this.name = name;
    }
}
//Bank: simulated withdrawal
class Drawing extends Thread{
    Account account;//account
    //How much did you withdraw
    int drawingMoney;
    //How much money do you have now
   int nowMoney;
    public Drawing(Account account, int drawingMoney, String name) {
        super(name);

        this.account = account;
        this.drawingMoney = drawingMoney;

    }

    @Override
    public void run() {
    //The object of the lock is the amount of change, which needs to be added, deleted and modified
        synchronized (account){
            if(account.money-drawingMoney<0){
                System.out.println(Thread.currentThread().getName()+"There's not enough money to withdraw");
                return;
            }
            //sleep can amplify the occurrence of problems
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //Card balance
            account.money=account.money-drawingMoney;
            //The money in your hand
            nowMoney=nowMoney+drawingMoney;
            System.out.println(account.name+"The balance is"+account.money);
            System.out.println(this.getName()+"Money in hand"+nowMoney);
        }
        }

}
Lock the object of the class whose properties will change

JUC security type test (java.util.concurrent)

Lock (lock display lock)

ReentrantLock (reentrant Lock) class implements Lock. It has the same concurrency and memory semantics as synchronized. ReentrantLock is commonly used in thread safety control, which can display locking and releasing locks

package com.Thread2;

import java.util.concurrent.locks.ReentrantLock;

public class JUCLock {
    public static void main(String[] args) {
        Lock lock =new Lock();
        new Thread(lock).start();
        new Thread(lock).start();
        new Thread(lock).start();


    }

    static class Lock implements Runnable{
    private  final  ReentrantLock lock=new ReentrantLock();
        int ticketName=10;

        @Override
        public void run() {
          lock.lock();
            try {
                while (true){                  
                    if (ticketName>0){
                        System.out.println(ticketName--);
                    }
                    else {
                        break;
                    }
                }
            }finally {
                lock.unlock();
            }

    }
    }
}

Note: Unlock and close the lock in try finally.

aggregate

package com.Thread2;

import java.util.concurrent.CopyOnWriteArrayList;
//A collection of test juc security types
public class TestJUC {
    public static void main(String[] args) throws InterruptedException {
       CopyOnWriteArrayList<String> list =new CopyOnWriteArrayList();
        for (int i = 0; i < 1000; i++) {
            new Thread(()->{
            list.add(Thread.currentThread().getName());

            }).start();
        }
        Thread.sleep(1000);
        System.out.println(list.size());

    }

}

synchronized vs Lock


1.Lock is a display lock (manually open and close the lock, don't forget to close the lock). synchronized is an implicit lock, which is automatically released out of the scope
2.Lock only has code block lock, and synchronized has code block lock and method lock
3. Using Lock lock, the JVM will spend less time to schedule threads and have better performance. And it has better extensibility (providing more subclasses)
4. Priority:
   lock > synchronization code block (has entered the method body and allocated corresponding resources) > synchronization method (outside the method body)

deadlock

meaning

Multiple threads occupy some shared resources and wait for the resources occupied by other threads to run. As a result, two or more threads are waiting for each other to release resources and stop execution. When a synchronization block has locks on more than two objects at the same time, deadlock may occur.

Avoidance method

Four necessary conditions for deadlock generation:
1. Mutually exclusive condition: a resource can only be used by one process at a time.
2. Request and hold condition: when a process is blocked by requesting resources, it will hold on to the resources obtained.
3. Conditions of non deprivation: the resources obtained by the process cannot be forcibly deprived until they are used up.
4. Circular waiting condition: a circular waiting resource relationship is formed between several processes.

Deadlock Demo:
Reason: use one resource at the same time

package com.Thread2;

public class DeadLock {
    public static void main(String[] args) {
        MakeUp makeUp=new MakeUp(0,"Sad little girl");
        MakeUp makeUp1=new MakeUp(1,"Vicious old woman");
     makeUp.start();
     makeUp1.start();



    }
    static class  LipsSick{

    }
    static   class Mirror{

     }

 static class MakeUp extends Thread{
        //Only one resource is needed, and only one is guaranteed by static
     static  LipsSick lipsSick=new LipsSick();
     static  Mirror  Mirror=new Mirror();

        int choice;
        String girlName;
        public MakeUp(int choice,String girlName){
            this.choice=choice;
            this.girlName=girlName;
        }
        @Override
        public void run() {
            makeup();
        }
        //Hold each other's locks, compete for the same resource, and form a deadlock
       private void  makeup(){
        if (choice==0){
           synchronized (lipsSick){
               System.out.println(this.girlName+"Got the lipstick");
             
                   Thread.sleep(1000);
          
           synchronized (Mirror){
               System.out.println(this.girlName+"I got the mirror");
               }
           }
        }
        else {
            synchronized (Mirror){
                System.out.println(this.girlName+"Got the lipstick");
          
                    Thread.sleep(2000);
             
                synchronized (lipsSick){
                    System.out.println(this.girlName+"I got the mirror");
                }
            }

        }

        }

    }
}

Unlock:

package com.Thread2;

public class DeadLock {
    public static void main(String[] args) {
        MakeUp makeUp=new MakeUp(0,"Sad little girl");
        MakeUp makeUp1=new MakeUp(1,"Vicious old woman");
     makeUp.start();
     makeUp1.start();



    }
    static class  LipsSick{

    }
    static   class Mirror{

     }

 static class MakeUp extends Thread{
        //Only one resource is needed, and only one is guaranteed by static
     static  LipsSick lipsSick=new LipsSick();
     static  Mirror  Mirror=new Mirror();

        int choice;
        String girlName;
        public MakeUp(int choice,String girlName){
            this.choice=choice;
            this.girlName=girlName;
        }
        @Override
        public void run() {
            makeup();
        }
       private void  makeup(){
        if (choice==0){
           synchronized (lipsSick){
               System.out.println(this.girlName+"Got the lipstick");
            
                   Thread.sleep(1000);
            

           }
            synchronized (Mirror){
                System.out.println(this.girlName+"I got the mirror");
            }
        }
        else {
            synchronized (Mirror){
                System.out.println(this.girlName+"Got the lipstick");
             
                    Thread.sleep(2000);
            }
            synchronized (lipsSick){
                System.out.println(this.girlName+"I got the mirror");
            }

        }

        }

    }
}

ps:b station crazy God notes

Tags: Java Back-end Multithreading

Posted on Wed, 20 Oct 2021 15:04:13 -0400 by clio-stylers