Multithreading and concurrent programming [thread object lock, deadlock and solution, thread concurrent cooperation, producer and consumer mode] (4) - comprehensive detailed explanation (learning summary --- from entry to deepening)

 

Table of contents

Use Class as thread object lock

Use custom object as thread object lock

Deadlock and Solution

Thread concurrent cooperation (producer/consumer mode)

 Implement the producer and consumer pattern


 

Use Class as thread object lock

 Grammatical structures:

synchronized(XX.class){
      //同步代码
 }

or

synchronized public static void accessVal()
/**
* 定义销售员工类
*/
class Sale{
    private String name;
    public Sale(String name){
this.name = name;
   }
    /**
     * 领取奖金
     */
    synchronized  public static void money(){
            try {
              System.out.println(Thread.currentThread().getName() + " 被领导表扬");
                Thread.sleep(500);
              System.out.println(Thread.currentThread().getName() + " 拿钱");
                Thread.sleep(500);
              System.out.println(Thread.currentThread().getName() + " 对公司表示感谢");
                Thread.sleep(500);
              System.out.println(Thread.currentThread().getName() + " 开开心心的拿钱走人");
           } catch (InterruptedExceptione) {
                e.printStackTrace();
           }
       }
}
class Programmer{
    private String name;
    public Programmer(String name){
         this.name = name;
   }
    /**
     * 打开电脑
     */
    synchronized  public  void computer(){
            try {
              System.out.println(this.name + " 接通电源");
                Thread.sleep(500);
              System.out.println(this.name + " 按开机按键");
                Thread.sleep(500);
              System.out.println(this.name + " 系统启动中");
                Thread.sleep(500);
              System.out.println(this.name + " 系统启动成功");
           } catch (InterruptedExceptione) {
                e.printStackTrace();
           }
   }
    /**
     * 编码
     */
    synchronized public void coding(){
            try {
                    System.out.println(this.name + " 双击Idea");
                Thread.sleep(500);
              System.out.println(this.name + " Idea启动完毕");
                Thread.sleep(500);
              System.out.println(this.name + " 开开心心的写代码");
           } catch (InterruptedExceptione) {
                e.printStackTrace();
           }
       }
    /**
     * 去卫生间
     */
    public void wc(){
        synchronized ("suibian") {
            try {
              System.out.println(this.name + " 打开卫生间门");
                Thread.sleep(500);
              System.out.println(this.name + " 开始排泄");
                Thread.sleep(500);
              System.out.println(this.name + " 冲水");
                Thread.sleep(500);System.out.println(this.name + " 离开卫生间");
           } catch (InterruptedExceptione) {
                e.printStackTrace();
           }
       }
   }
    /**
     * 领取奖金
     */
    public void money(){
        synchronized (Programmer.class) {
            try {
              System.out.println(this.name + " 被领导表扬");
                Thread.sleep(500);
              System.out.println(this.name + " 拿钱");
                Thread.sleep(500);
              System.out.println(this.name + " 对公司表示感谢");
                Thread.sleep(500);
              System.out.println(this.name + " 开开心心的拿钱走人");
           } catch (InterruptedExceptione) {
                e.printStackTrace();
   }
       }
   }
}
/**
* 打开电脑的工作线程
*/
class Working1 extends Thread{
    private  Programmer p;
    public Working1(Programmer p){
        this.p = p;
   }
    @Override
    public void run() {
        this.p.computer();
   }
}
/**
* 编写代码的工作线程
*/
class Working2 extends Thread{
    private  Programmer p;
    public Working2(Programmer p){
        this.p = p;
   }
    @Override
    public void run() {
        this.p.coding();
   }
}
/**
* 去卫生间的线程
*/
class WC extends Thread{
    private  Programmer p;
    public WC(Programmer p){
        this.p = p;
   }
    @Override
    public void run() {
        this.p.wc();
   }
}
/**
* 程序员领取奖金
*/
class ProgrammerMoney extends Thread{
    private  Programmer p;
    public ProgrammerMoney(Programmer p){
        this.p = p;
   }
    @Override
    public void run() {
        this.p.money();
   }
}
/**
* 销售部门领取奖金
*/
class SaleMoney extends  Thread{
    private  Sale p;
    public SaleMoneyThread(Sale p){
        this.p = p;
   }
    @Override
    public void run() {
        this.p.money();
   }
}
public class TestSyncThread {
    public static void main(String[] args)
{
       /* Programmer p = new Programmer("张三");
        Programmer p1 = new Programmer("李四");
        new ProgrammerMoney(p).start();
        new ProgrammerMoney(p1).start();*/
        
        Sale s = new Sale("张晓丽");
        Sale s1 = new Sale("王晓红");
        new SaleMoney(s).start();
        new SaleMoney(s1).start();
   }
}

Use custom object as thread object lock

Grammatical structures:

synchronized(自定义对象){
      //同步代码
}
/**
* 定义销售员工类
*/
class Sale{
    private String name;
    public Sale(String name){
        this.name = name;
   }
    /**
     * 领取奖金
     */
    synchronized  public static void money(){
            try {
                System.out.println(Thread.currentThread(). getName() + " 被领导表扬");
                Thread.sleep(500);
              System.out.println(Thread.currentThread().getName() + " 拿钱");
                Thread.sleep(500);
              System.out.println(Thread.currentThread().getName() + " 对公司表示感谢");
                Thread.sleep(500);
              System.out.println(Thread.currentThread().getName() + " 开开心心的拿钱走人");
           } catch (InterruptedExceptione) {
                e.printStackTrace();
           }
       }
}
class Programmer{
    private String name;
    public Programmer(String name){
        this.name = name;
   }
    /**
     * 打开电脑
     */
    synchronized  public  void computer(){
            try {
                   System.out.println(this.name + " 接通电源");
                   Thread.sleep(500);
                   System.out.println(this.name + " 按开机按键");
                   Thread.sleep(500);
                   System.out.println(this.name + " 系统启动中");
                Thread.sleep(500);
              System.out.println(this.name + " 系统启动成功");
           } catch (InterruptedException e) {
                e.printStackTrace();
           }
   }
    /**
     * 编码
     */
    synchronized public void coding(){
            try {
              System.out.println(this.name + " 双击Idea");
                Thread.sleep(500);
              System.out.println(this.name + " Idea启动完毕");
                Thread.sleep(500);
              System.out.println(this.name + " 开开心心的写代码");
           } catch (InterruptedException e) {
                e.printStackTrace();
           }
       }
    /**
     * 去卫生间
     */
    public void wc(){
        synchronized ("suibian") {
            try {
               System.out.println(this.name + " 打开卫生间门");
                Thread.sleep(500);
               System.out.println(this.name + " 开始排泄");
                Thread.sleep(500);
               System.out.println(this.name + " 冲水");
                Thread.sleep(500);
               System.out.println(this.name + " 离开卫生间");
           } catch (InterruptedException e) {
                e.printStackTrace();
           }
       }
 }
    /**
     * 领取奖金
     */
    public void money(){
        synchronized (Programmer.class) {
            try {
                 System.out.println(this.name + " 被领导表扬");
                Thread.sleep(500);
                 System.out.println(this.name + " 拿钱");
                Thread.sleep(500);
                System.out.println(this.name + " 对公司表示感谢");
                Thread.sleep(500);
                System.out.println(this.name + " 开开心心的拿钱走人");
           } catch (InterruptedException e) {
                e.printStackTrace();
           }
       }
   }
}
class Manager{
    private String name;
    public Manager(String name){
        this.name = name;
}
    public String getName(){
        return this.name;
   }
    /**
     * 敬酒
     */
    public void cheers(String mName,String eName){
            try {
                System.out.println(mName + " 来到 " + eName + " 面前");
                Thread.sleep(500);
                System.out.println(eName + " 拿起酒杯");
                Thread.sleep(500);
                System.out.println(mName + " 和 " + eName + " 干杯");
           } catch (InterruptedException e) {
                e.printStackTrace();
           }
   }
}
/**
* 打开电脑的工作线程
*/
class Working1 extends Thread{
    private  Programmer p;
    public Working1(Programmer p){
        this.p = p;
   }
  @Override
    public void run() {
        this.p.computer();
   }
}
/**
* 编写代码的工作线程
*/
class Working2 extends Thread{
    private  Programmer p;
    public Working2(Programmer p){
        this.p = p;
   }
    @Override
    public void run() {
        this.p.coding();
   }
}
/**
* 去卫生间的线程
*/
class WC extends Thread{
    private  Programmer p;
    public WC(Programmer p){
        this.p = p;
   }
    @Override
    public void run() {
        this.p.wc();
   }
}
/**
* 程序员领取奖金
*/
class ProgrammerMoney extends Thread{
    private  Programmer p;
    public ProgrammerMoney(Programmer p){
        this.p = p;
   }
    @Override
    public void run() {
        this.p.money();
   }
}
/**
* 销售部门领取奖金
*/
class SaleMoneyThread extends  Thread{
    private  Sale p;
    public SaleMoneyThread(Sale p){
        this.p = p;
   }
    @Override
    public void run() {
        this.p.money();
   }
}
/**
* 敬酒线程类
*/
class CheersThread extends Thread{
    private Manager manager;
    private String name;
    public CheersThread(String name,Manager manager){
        this.name = name;
        this.manager = manager;
   }
    @Override
    public void run() {
        synchronized (this.manager) {
          
this.manager.cheers(this.manager.getName() , name);
       }
   }
}
public class TestSyncThread {
    public static void main(String[] args)
{
        Manager manager = new Manager("张三丰");
        new CheersThread("张三",manager).start();
        new CheersThread("李四",manager).start();
   }
}

Deadlock and Solution

The concept of deadlock

 "Deadlock" refers to: multiple threads each occupy some shared resources, and wait for each other's resources occupied by other threads to proceed, resulting in two or more threads waiting for each other to release resources, and they all stop executing.

When a synchronization block needs to own "locks of more than two objects" at the same time, the problem of "deadlock" may occur. For example, "makeup thread" needs to have both "mirror object" and "lipstick object" to run the synchronization block. Then, in actual operation, "little girl's makeup thread" has a "mirror object", and "big girl's makeup thread" has a "lipstick object", and they are all waiting for each other to release resources before they can make up. In this way, the two threads form a "deadlock state" in which they wait for each other and cannot continue to run.

 Deadlock Case Demonstration

/**
* 口红类
*/
   class Lipstick{
     }
/**
* 镜子类
*/
   class Mirror{
   }
/**
* 化妆线程类
*/
class Makeup extends Thread{
    private int flag; //flag=0:拿着口红。 flag!=0:拿着镜子
    private String girlName;
    static Lipstick lipstick = new Lipstick();
    static Mirror mirror = new Mirror();
    public Makeup(int flag,String girlName){
        this.flag  = flag;
        this.girlName = girlName;
   }
    @Override
    public void run() {
        this.doMakeup();
   }
    /**
     * 开始化妆
     */
    public void doMakeup(){
        if(flag == 0){
            synchronized (lipstick){
              System.out.println(this.girlName+" 拿着口红");
                try {
                    Thread.sleep(1000);
               } catch (InterruptedException e) {
                    e.printStackTrace();
               }
                synchronized (mirror){
               System.out.println(this.girlName+" 拿着镜子");
               }
           }
       }else{
            synchronized (mirror){
              System.out.println(this.girlName+" 拿着镜子");
                try {
                    Thread.sleep(2000);
               } catch(InterruptedException e) {
                    e.printStackTrace();
               }
                synchronized (lipstick){
                  System.out.println(this.girlName+" 拿着口红");
               }
           }
       }
   }
}
public class DeadLockThread {
    public static void main(String[] args) {
        new Makeup(0,"大丫").start();
        new Makeup(1,"小丫").start();
   }
}

Solution to deadlock problem

The deadlock is caused by "the synchronization block needs to hold multiple object locks at the same time". To solve this problem, the idea is very simple: the same code block should not hold two object locks at the same time.

/**
* 口红类
*/
    class Lipstick{
     }
/**
* 镜子类
*/
    class Mirror{
    }
/**
* 化妆线程类
*/
class Makeup extends Thread{
    private int flag; //flag=0:拿着口红。 flag!=0:拿着镜子
    private String girlName;
    static Lipstick lipstick = new Lipstick();
    static Mirror mirror = new Mirror();
    public void setFlag(int flag) {
        this.flag = flag;
      }
    public void setGirlName(String girlName)
      {
        this.girlName = girlName;
      }
    @Override
    public void run() {
        this.doMakeup();
     }
    /**
     * 开始化妆
     */
    public void doMakeup(){
        if(flag == 0){
            synchronized (lipstick){
              System.out.println(this.girlName+" 拿着口红");
                try {
                    Thread.sleep(1000);
               } catch(InterruptedException e) {
                    e.printStackTrace();
               }
           }
            synchronized (mirror){
             System.out.println(this.girlName+" 拿着镜子");
           }
       }else{
            synchronized (mirror){
              System.out.println(this.girlName+" 拿着镜子");
                try {
                    Thread.sleep(2000);
               } catch(InterruptedException e) {
                    e.printStackTrace();
               }
           }
            synchronized (lipstick){
              System.out.println(this.girlName+" 拿着口红");
           }
       }
   }
}
public class DeadLockThread {
    public static void main(String[] args) {
        Makeup makeup = new Makeup();
        makeup.setFlag(0);
        makeup.setGirlName("大丫");
        Makeup makeup1 = new Makeup();
        makeup1.setFlag(1);
        makeup1.setGirlName("小丫");
        makeup.start();
        makeup1.start();
   }
}

Solution to deadlock problem

The deadlock is caused by "the synchronization block needs to hold multiple object locks at the same time". To solve this problem, the idea is very simple: the same code block should not hold two object locks at the same time.

/**
* 口红类
*/
     class Lipstick{
     }
/**
* 镜子类
*/
    class Mirror{
    }
/**
* 化妆线程类
*/
class Makeup extends Thread{
    private int flag; //flag = 0 :拿着口红,flag != 0 :拿着镜子
  private String girlName;
    static Lipstick lipstick = new Lipstick();
    static Mirror mirror = new Mirror();
    public Makeup(int flag,String girlName){
        this.flag = flag;
        this.girlName = girlName;
   }
    @Override
    public void run() {
        this.doMakeup();
   }
    /**
     * 开始化妆
     */
    public void doMakeup(){
        if(this.flag == 0){
            synchronized (lipstick){
               System.out.println(this.girlName+" 拿着口红");
                try {
                    Thread.sleep(1000);
               } catch(InterruptedException e) {
                    e.printStackTrace();
               }
           }
 synchronized (mirror){
              System.out.println(this.girlName+" 拿着镜子");
           }
       }else{
            synchronized (mirror){
              System.out.println(this.girlName+" 拿着镜子");
                try {
                    Thread.sleep(2000);
               } catch(InterruptedException e) {
                    e.printStackTrace();
               }
           }
            synchronized (lipstick){
              System.out.println(this.girlName+" 拿着口红");
           }
       }
   }
}
public class DeadLockThread {
    public static void main(String[] args) {
  new Makeup(0,"小丫").start();
        new Makeup(1,"大丫").start();
   }
}

Thread concurrent cooperation (producer/consumer mode)

 In a multi-threaded environment, we often need the concurrency and cooperation of multiple threads. At this time, it is necessary to understand an important multi-threaded concurrent cooperation model "producer/consumer mode".

 Character introduction

   What is a producer?

      The producer refers to the module responsible for producing data (here the module may be: method, object, thread, process).

  What is a consumer?

    Consumers refer to modules responsible for processing data (here modules may be: methods, objects, threads, processes).

  What is a buffer?

    Consumers cannot directly use the producer's data, there is a "buffer" between them. The producer puts the produced data into the "buffer", and the consumer takes the data to be processed from the "buffer".

 The buffer is the core to achieve concurrency. The setting of the buffer has two advantages:

1 Realize the concurrent cooperation of threads

After having a buffer, the producer thread only needs to place data in the buffer, and does not need to care about the consumer's consumption; similarly, the consumer only needs to process the data from the buffer, and does not need to care about the producer's production. Case. In this way, the separation of "producer thread" and "consumer thread" is logically realized, and the coupling between producers and consumers is released.

2 Solve uneven busyness and improve efficiency

When the producer is slow in producing data, there is still data in the buffer, which does not affect consumer consumption; when the consumer is slow in processing data, the producer can still continue to place data in the buffer.

 Implement the producer and consumer pattern

create buffer

/**
* 定义馒头类
*/
class ManTou{
    private int id;
    public ManTou(int id){
        this.id = id;
   }
  public int getId(){
        return this.id;
   }
}
/**
* 定义缓冲区类
*/
class SyncStack{
    //定义存放馒头的盒子
    private ManTou[] mt = new ManTou[10];
    //定义操作盒子的索引
    private int index;
    /**
     * 放馒头
     */
    public synchronized void push(ManTou manTou){
        //判断盒子是否已满
        while(this.index == this.mt.length){
            try {
                /**
                 * 语法:wait(),该方法必须要在 synchronized块中调用。
                 * wait执行后,线程会将持有的对象锁释放,并进入阻塞状态,
                 * 其他需要该对象锁的线程就可以继续运行了。
                 */
                this.wait();
               } catch (InterruptedException e){
                e.printStackTrace();
           }
       }
        //唤醒取馒头的线程
        /**
         * 语法:该方法必须要在synchronized块中调用。
         * 该方法会唤醒处于等待状态队列中的一个线程。
         */
        this.notify();
        this.mt[this.index] = manTou;
        this.index++;
   }
    /**
     * 取馒头
     */
    public synchronized ManTou pop(){
        while(this.index == 0){
            try {
                /**
                 * 语法:wait(),该方法必须要在synchronized块中调用。
                 * wait执行后,线程会将持有的对象锁释放,并进入阻塞状态,
                 * 其他需要该对象锁的线程就可以继续运行了。
                 */
                this.wait();
           } catch (InterruptedException e)
           {
                e.printStackTrace();
           }
       }
        this.notify();
        this.index--;
        return this.mt[this.index];
   }
}
public class TestProduceThread {
    public static void main(String[] args) {
      
   }
}

Create a producer consumer thread

/**
* 定义馒头类
*/
class ManTou{
    private int id;
    public ManTou(int id){
        this.id = id;
   }
    public int getId(){
        return this.id;
   }
}
/**
* 定义缓冲区类
*/
class SyncStack{
    //定义存放馒头的盒子
    private ManTou[] mt = new ManTou[10];
    //定义操作盒子的索引
    private int index;
    /**
     * 放馒头
     */
    public synchronized void push(ManTou manTou){
        //判断盒子是否已满
        while(this.index == this.mt.length)
          {
            try {
                /**
                 * 语法:wait(),该方法必须要在 synchronized块中调用。
                 * wait执行后,线程会将持有的对象锁释放,并进入阻塞状态,
                 * 其他需要该对象锁的线程就可以继续运行了。
                 */
                this.wait();
           } catch (InterruptedException e) {
                e.printStackTrace();
          }
       }
        //唤醒取馒头的线程
        /**
         * 语法:该方法必须要在synchronized块中调用。
         * 该方法会唤醒处于等待状态队列中的一个线程。
         */
        this.notify();
        this.mt[this.index] = manTou;
        this.index++;
   }
    /**
     * 取馒头
     */
    public synchronized ManTou pop(){
        while(this.index == 0){
            try {
                /**
                 * 语法:wait(),该方法必须要在synchronized块中调用。
                 * wait执行后,线程会将持有的对象锁释放,并进入阻塞状态,
                 * 其他需要该对象锁的线程就可以继续运行了。
                 */
                this.wait();
           } catch (InterruptedException e) {
                e.printStackTrace();
           }
       }
        this.notify();
        this.index--;
        return this.mt[this.index];
   }
}
/**
* 定义生产者线程类
*/
class ShengChan extends Thread{
    private SyncStack ss;
    public ShengChan(SyncStack ss){
        this.ss = ss;
   }
    @Override
    public void run() {
       for(int i=0;i<10;i++){
           System.out.println("生产馒头:"+i);
           ManTou manTou = new ManTou(i);
           this.ss.push(manTou);
       }
   }
}
/**
* 定义消费者线程类
*/
class XiaoFei extends Thread{
    private SyncStack ss;
    public XiaoFei(SyncStack ss){
        this.ss = ss;
   }
    @Override
    public void run() {
        for(int i=0;i<10;i++){
           ManTou manTou = this.ss.pop();
            System.out.println("消费馒头:"+i);
       }
   }
}
public class ProduceThread {
    public static void main(String[] args)
{
        SyncStack ss = new SyncStack();
        new ShengChan(ss).start();
        new XiaoFei(ss).start();
   }
}

Summary of thread concurrency and cooperation

Thread concurrent cooperation (also called thread communication)

   Producer consumer pattern:

1 Producers and consumers share the same resource, and producers and consumers depend on each other and are mutually conditioned.

2 For producers, before producing products, consumers have to enter a waiting state. After the product is produced, consumers need to be notified immediately for consumption.

3 For consumers, after consumption, the producer must be notified that the consumption has ended, and new products need to be produced for consumption. 4 In the producer consumer problem, only synchronized is not enough. Synchronized can prevent concurrent updates to the same shared resource, achieving synchronization but synchronized cannot be used to achieve message passing (communication) between different threads.

5 What methods does the thread use for message passing (communication)? See the summary below:

 6 The above methods are methods of java.lang.Object class;

Both can only be used in synchronous methods or synchronous code blocks, otherwise an exception will be thrown.

OldLu suggested that this mode will be used extensively in actual development, especially in "architecture design". For beginners, it is enough to understand. If you are promoted to intermediate and senior developers, this is what you must master.

Guess you like

Origin blog.csdn.net/m0_58719994/article/details/131648388