Multi-threaded and concurrent programming [Daemon thread, thread synchronization] (3) - comprehensive detailed explanation (learning summary --- from entry to deepening)

 

 

Table of contents

daemon thread

 What is a daemon thread

 The use of daemon threads

thread synchronization

Implement thread synchronization

The use of thread synchronization


daemon thread

 What is a daemon thread

  There are two types of threads in Java:

        User Thread (user thread): It is a custom thread in the application.

        Daemon Thread: For example, garbage collection thread is the most typical daemon thread.

 The daemon thread (that is, Daemon Thread) is a service thread. To be precise, it is to serve other threads. This is its role, and there is only one other thread, that is, the user thread.

 Daemon thread features :

      Daemon threads die as user threads die.

The difference between daemon threads and user threads :

User threads do not die with the death of the main thread. There are only two situations in which user threads will die, one is abnormal termination in run. 2 The run is executed normally, and the thread dies.

The daemon thread dies with the death of the user thread, and the daemon thread will also die when the user thread dies.

 The use of daemon threads

/**
* 守护线程类
*/
class Daemon implements  Runnable{
    @Override
    public void run() {
        for(int i=0;i<20;i++){
              System.out.println(Thread.currentThread().getName()+" "+i);
            try {
                Thread.sleep(2000);
           } catch (InterruptedException e){
                e.printStackTrace();
           }
       }
   }
}
class UsersThread implements Runnable{
    @Override
    public void run() {
        Thread t = new Thread(new Daemon(),"Daemon");
        //将该线程设置为守护线程
        t.setDaemon(true);
        t.start();
        for(int i=0;i<5;i++){
          System.out.println(Thread.currentThread().getName()+" "+i);
            try {
                Thread.sleep(500);
           } catch (InterruptedException e){
                e.printStackTrace();
           }
       }
   }
}
public class DaemonThread {
    public static void main(String[] args)throws Exception {
        Thread t = new Thread(new UsersThread(),"UsersThread");
        t.start();
        Thread.sleep(1000);
        System.out.println("主线程结束");
   }
}

thread synchronization

What is thread synchronization

thread conflict

 Synchronization question raised

In real life, we will encounter the problem of "multiple people want to use the same resource". For example: There is only one computer in the classroom, and multiple people want to use it. The natural solution is to line up next to the computer. After the previous person finishes using it, the latter person will use it again.

 The concept of thread synchronization

When dealing with multithreading issues, multiple threads access the same object, and some threads also want to modify this object. At this time, we need to use "thread synchronization". Thread synchronization is actually a waiting mechanism. Multiple threads that need to access this object at the same time enter the waiting pool of this object to form a queue, and wait for the previous thread to be used before the next thread can use it.

Thread Conflict Case Demo 

We use the classic case of bank withdrawal to demonstrate the thread conflict phenomenon. The basic process of bank withdrawals can basically be divided into the following steps.

(1) The user enters the account and password, and the system judges whether the user's account and password match.

(2) The user enters the withdrawal amount

(3) The system judges whether the account balance is greater than or equal to the withdrawal amount

(4) If the balance is greater than or equal to the withdrawal amount, the withdrawal is successful; if the balance is less than the withdrawal amount, the withdrawal fails.

/**
* 账户类
*/
class Account{
    //账号
    private String accountNo;
    //账户的余额
    private double balance;
    public Account() {
   }
    public Account(String accountNo, double balance) {
        this.accountNo = accountNo;
        this.balance = balance;
   }
    public String getAccountNo() { return accountNo;
   }
    public void setAccountNo(String accountNo) {
        this.accountNo = accountNo;
   }
    public double getBalance() {
        return balance;
   }
    public void setBalance(double balance) {
        this.balance = balance;
   }
}
/**
* 取款线程
*/
class DrawThread implements Runnable{
    //账户对象
    private Account account;
    //取款金额
    private double drawMoney;
    public DrawThread(Account account,double drawMoney){
        this.account = account;
        this.drawMoney = drawMoney;
   }
    /**
     * 取款线程
 */
    @Override
    public void run() {
        //判断当前账户余额是否大于或等于取款金额
        if(this.account.getBalance() >= this.drawMoney){
          System.out.println(Thread.currentThread().getName()+" 取钱成功!吐出钞
票:"+this.drawMoney);
            try {
                Thread.sleep(1000);
           } catch (InterruptedException e){
                e.printStackTrace();
           }
            //更新账户余额
          this.account.setBalance(this.account.getBalance()- this.drawMoney);
            System.out.println("\t 余额为:"+this.account.getBalance());
       }else{
          System.out.println(Thread.currentThread().getName()+" 取钱失败,余额不足");
       }
   }
}
public class TestDrawMoneyThread {
    public static void main(String[] args) {
        Account account = new Account("1234",1000);
        new Thread(new DrawThread(account,800),"老公").start();
        new Thread(new DrawThread(account,800),"老婆").start();
   }
}

Implement thread synchronization

Since multiple threads of the same process share the same storage space, while bringing convenience, it also brings the problem of access conflicts. The Java language provides a special mechanism to resolve this conflict, effectively avoiding the problem caused by the same data object being accessed by multiple threads at the same time. This mechanism is the synchronized keyword.

 Synchronized syntax structure:

synchronized(锁对象){ 
   同步代码
 }

Issues to consider when using the synchronized keyword:

    It is necessary to have the ability of thread mutual exclusion (thread mutual exclusion: parallel to serial) for that part of the code during execution.

   Codes in which threads need to have mutual exclusion capabilities (determined by synchronized lock objects).

It includes two usages:

synchronized methods and synchronized blocks.

 1 synchronized method 

    Declare by adding the synchronized keyword in the method declaration, the syntax is as follows:

    

public  synchronized  void accessVal(int newVal);

Synchronized is used in method declarations: before or after the access control character (public). At this time, when the synchronized method under the same object is executed in multiple threads, the method is synchronized, that is, only one thread can enter the method at a time. If other threads want to call the method at this time, they can only wait in line. The current thread (That is, the thread inside the synchronized method) After the method is executed, other threads can enter.

2 synchronized blocks

The defect of the synchronized method: If a large method is declared as synchronized, it will greatly affect the efficiency. Java provides us with a better solution, which is the synchronized block. Blocks allow us to precisely control specific "member variables", narrow the scope of synchronization, and improve efficiency.

Modify thread conflict case demo

/**
* 账户类
*/
class Account{
    //账号
    private String accountNO;
    //账户余额
    private double balance;
    public Account() {
   }
    public Account(String accountNO, double balance) {
        this.accountNO = accountNO;
        this.balance = balance;
   }
    public String getAccountNO() {
        return accountNO;
   }
    public void setAccountNO(String accountNO) {
        this.accountNO = accountNO;
}
    public double getBalance() {
        return balance;
   }
    public void setBalance(double balance) {
        this.balance = balance;
   }
}
/**
* 取款线程
*/
class DrawThread implements Runnable{
    //账户对象
    private Account account;
    //取款金额
    private double drawMoney;
    public DrawThread(){
   }
    public DrawThread(Account account,double drawMoney){
        this.account = account;
        this.drawMoney = drawMoney;
   }
    /**
     * 取款线程体
     */
    @Override
 public void run() {
        synchronized (this.account){
            //判断当前账户余额是否大于或等于取款金额
            if(this.account.getBalance() >= this.drawMoney){
              System.out.println(Thread.currentThread().getName()+" 取钱成功!突出钞票"+this.drawMoney);
                try {
                    Thread.sleep(1000);
               } catch(InterruptedException e) {
                    e.printStackTrace();
               }
                //更新账户余额
              this.account.setBalance(this.account.getBalance() - this.drawMoney);
                System.out.println("\t 余额为:"+this.account.getBalance());
           }else{
              System.out.println(Thread.currentThread().getName()+" 取钱失败,余额不足");
           }
       }
   }
}
public class TestDrawMoneyThread {
    public static void main(String[] args) {
        Account account = new Account("1234",1000);
        new Thread(new DrawThread(account,800),"老公").start();
        new Thread(new DrawThread(account,800),"老婆").start();
   }
}

The use of thread synchronization

Use this as the thread object lock

 Grammatical structures:

synchronized(this){
      //同步代码
 }

or

public  synchronized  void accessVal(int newVal){
    //同步代码
}
/**
* 定义程序员类
*/
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();
           }
       }
}
/**
* 打开电脑的工作线程
*/
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();
   }
}
public class TestSyncThread {
    public static void main(String[] args) {
        Programmer p = new Programmer("张三");
        new Working1(p).start();
        new Working2(p).start();
   }
}

Use string as thread object lock

 Grammatical structures:

synchronized(“字符串”){
      //同步代码
 }
/**
* 定义程序员类
*/
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();
           }
       }
   }
}
/**
* 打开电脑的工作线程
*/
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();
   }
}
public class TestSyncThread {
    public static void main(String[] args)
{
        Programmer p = new Programmer("张三");
        Programmer p1 = new Programmer("李四");
        Programmer p2 = new Programmer("王五");
        new WC(p).start();
        new WC(p1).start();
        new WC(p2).start();
   }
}

Guess you like

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