JAVA Deepening Chapter_32 – Thread synchronization synchronized syntax structure used by threads [with detailed description and code]

Thread synchronization

What is thread synchronization

Asking synchronization issues

In real life, we will encounter the problem of “multiple people want to use the same resource”. For example: In the classroom, there is only one computer and many people want to use it. The natural solution is to line up next to the computer. After the previous person has finished using it, the next person can use it again.

The concept of thread synchronization

When dealing with multi-threading issues, multiple threads access the same object, and some threads also want to modify the 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 finish using it before the next thread uses it.

Thread conflict case demonstration

We use a classic case of bank withdrawal to demonstrate the thread conflict phenomenon.

The basic process of withdrawing money from the bank can basically be divided into the following steps.

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

(2) The user enters the withdrawal amount

(3) The system determines 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.

/**
 *Account type
 */
class Account{<!-- -->
  //account
  private String accountNo;
  //The balance of the account
  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;
   }
}
/**
 * Withdrawal thread
 */
class DrawThread implements Runnable{<!-- -->
  //account object
  private Account account;
  //Withdrawal amount
  private double drawMoney;
  public DrawThread(Account account,double drawMoney){<!-- -->
    this.account = account;
    this.drawMoney = drawMoney;
   }


  /**
   * Withdrawal thread
   */
  @Override
  public void run() {<!-- -->
    //Determine whether the current account balance is greater than or equal to the withdrawal amount
    if(this.account.getBalance() >= this.drawMoney){<!-- -->
      System.out.println(Thread.currentThread().getName() + "Withdraw money successfully! Spit out banknotes: " + this.drawMoney);
      try {<!-- -->
        Thread.sleep(1000);
       } catch (InterruptedException e) {<!-- -->
        e.printStackTrace();
       }
      //Update account balance
      this.account.setBalance(this.account.getBalance()- this.drawMoney);
      System.out.println("\tThe balance is: " + this.account.getBalance());
     }else{<!-- -->
      System.out.println(Thread.currentThread().getName() + "Withdrawal failed, insufficient balance");
     }
   }
}


public class TestDrawMoneyThread {<!-- -->
  public static void main(String[] args) {<!-- -->
    Account account = new Account("1234",1000);
    new Thread(new DrawThread(account,800),"husband").start();
    new Thread(new DrawThread(account,800),"wife").start();
   }
}

Implement thread synchronization

Since multiple threads of the same process share the same storage space, it not only brings convenience, but 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(lock object){<!-- -->
sync code
}

Issues to consider when using the synchronized keyword:

  • That part of the code needs to have thread mutual exclusion capabilities during execution (thread mutual exclusion: parallel to serial).
  • The code in which threads needs to be mutually exclusive (determined by the synchronized lock object).

It includes two usages:

synchronized methods and synchronized blocks.

  • synchronized method

    Declared by adding the synchronized keyword to the method declaration, the syntax is as follows:

public synchronized void accessVal(int newVal);

  • synchronized is used when declaring a method: placed 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 executing the method, other threads can enter.

  • synchronized block

    Defects of the synchronized method: If a large method is declared synchronized, the efficiency will be greatly affected.

    Java provides us with a better solution, which is synchronized blocks. Blocks allow us to precisely control specific “member variables”, narrow the scope of synchronization, and improve efficiency.

Modify thread conflict case demonstration

/**
 *Account type
 */
class Account{<!-- -->
  //account
  private String accountNO;
  //Account Balance
  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;
   }
}
/**
 * Withdrawal thread
 */
class DrawThread implements Runnable{<!-- -->
  //account object
  private Account account;
  //Withdrawal amount
  private double drawMoney;
  public DrawThread(){<!-- -->
   }
  public DrawThread(Account account,double drawMoney){<!-- -->
    this.account = account;
    this.drawMoney = drawMoney;
   }
  /**
   * Withdrawal thread body
   */
  @Override
  public void run() {<!-- -->
    synchronized (this.account){<!-- -->
      //Determine whether the current account balance is greater than or equal to the withdrawal amount
      if(this.account.getBalance() >= this.drawMoney){<!-- -->
        System.out.println(Thread.currentThread().getName() + "Withdrawing money successfully! Highlight the banknote" + this.drawMoney);
        try {<!-- -->
          Thread.sleep(1000);
         } catch (InterruptedException e) {<!-- -->
          e.printStackTrace();
         }
        //Update account balance
        this.account.setBalance(this.account.getBalance() - this.drawMoney);
        System.out.println("\tThe balance is: " + this.account.getBalance());
       }else{<!-- -->
        System.out.println(Thread.currentThread().getName() + "Withdrawal failed, insufficient balance");
       }
     }
   }
}
public class TestDrawMoneyThread {<!-- -->
  public static void main(String[] args) {<!-- -->
    Account account = new Account("1234",1000);
    new Thread(new DrawThread(account,800),"husband").start();
    new Thread(new DrawThread(account,800),"wife").start();
   }
}

The use of thread synchronization

Use this as the thread object lock

Grammatical structures:

synchronized(this){<!-- -->
//Synchronization code
}

or

public synchronized void accessVal(int newVal){<!-- -->
//Synchronization code
}

/**
 * Define programmer class
 */
class Programmer{<!-- -->
  private String name;
  public Programmer(String name){<!-- -->
    this.name = name;
   }
  /**
   * turn on computer
   */
  synchronized public void computer(){<!-- -->
      try {<!-- -->
        System.out.println(this.name + "Power on");
        Thread.sleep(500);
        System.out.println(this.name + "Press the power button");
        Thread.sleep(500);
        System.out.println(this.name + "System is starting");
        Thread.sleep(500);
        System.out.println(this.name + "System startup successful");
       } catch (InterruptedException e) {<!-- -->
        e.printStackTrace();
       }
   }
  /**
   * encoding
   */
  synchronized public void coding(){<!-- -->
      try {<!-- -->
        System.out.println(this.name + "Double-click Idea");
        Thread.sleep(500);
        System.out.println(this.name + "Idea startup completed");
        Thread.sleep(500);
        System.out.println(this.name + "Write code happily");
       } catch (InterruptedException e) {<!-- -->
        e.printStackTrace();
       }
     }
}


/**
 * Open the computer's working thread
 */
class Working1 extends Thread{<!-- -->
  private Programmer p;
  public Working1(Programmer p){<!-- -->
    this.p = p;
   }
  @Override
  public void run() {<!-- -->
    this.p.computer();
   }
}


/**
 * Worker thread for writing code
 */
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("Zhang San");
    new Working1(p).start();
    new Working2(p).start();
   }
}

Use string as thread object lock

Grammatical structures:

synchronized("string"){<!-- -->
//Synchronization code
}

/**
 * Define programmer class
 */
class Programmer{<!-- -->
  private String name;
  public Programmer(String name){<!-- -->
    this.name = name;
   }
  /**
   * turn on computer
   */
  synchronized public void computer(){<!-- -->
      try {<!-- -->
        System.out.println(this.name + "Power on");
        Thread.sleep(500);
        System.out.println(this.name + "Press the power button");
        Thread.sleep(500);
        System.out.println(this.name + "System is starting");
        Thread.sleep(500);
        System.out.println(this.name + "System startup successful");
       } catch (InterruptedException e) {<!-- -->
        e.printStackTrace();
       }
   }
  /**
   * encoding
   */
  synchronized public void coding(){<!-- -->
      try {<!-- -->
        System.out.println(this.name + "Double-click Idea");
        Thread.sleep(500);
        System.out.println(this.name + "Idea startup completed");
        Thread.sleep(500);
        System.out.println(this.name + "Write code happily");
       } catch (InterruptedException e) {<!-- -->
        e.printStackTrace();
       }
     }
  /**
   * Go to the bathroom
   */
  public void wc(){<!-- -->
    synchronized ("suibian") {<!-- -->
      try {<!-- -->
        System.out.println(this.name + "Open the bathroom door");
        Thread.sleep(500);
        System.out.println(this.name + "Start excreting");
        Thread.sleep(500);
        System.out.println(this.name + "flush");
        Thread.sleep(500);
        System.out.println(this.name + "Leave the bathroom");
       } catch (InterruptedException e) {<!-- -->
        e.printStackTrace();
       }
     }
   }
}


/**
 * Open the computer's working thread
 */
class Working1 extends Thread{<!-- -->
  private Programmer p;
  public Working1(Programmer p){<!-- -->
    this.p = p;
   }
  @Override
  public void run() {<!-- -->
    this.p.computer();
   }
}


/**
 * Worker thread for writing code
 */
class Working2 extends Thread{<!-- -->
  private Programmer p;
  public Working2(Programmer p){<!-- -->
    this.p = p;
   }
  @Override
  public void run() {<!-- -->
    this.p.coding();
   }
}


/**
 * Thread to go to the bathroom
 */
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("Zhang San");
    Programmer p1 = new Programmer("李思");
    Programmer p2 = new Programmer("王五");
    new WC(p).start();
    new WC(p1).start();
    new WC(p2).start();
   }
}

Use Class as thread object lock

Grammatical structures:

synchronized(XX.class){<!-- -->
//Synchronization code
}

or

synchronized public static void accessVal()

/**
 * Define sales employee class
 */
class Sale{<!-- -->
  private String name;
  public Sale(String name){<!-- -->
    this.name = name;
   }
  /**
   * Claim your bonus
   */
  synchronized public static void money(){<!-- -->
      try {<!-- -->
        System.out.println(Thread.currentThread().getName() + "Praised by the leader");
        Thread.sleep(500);
        System.out.println(Thread.currentThread().getName() + "Get money");
        Thread.sleep(500);
        System.out.println(Thread.currentThread().getName() + "Thank you to the company");
        Thread.sleep(500);
        System.out.println(Thread.currentThread().getName() + "Happily take the money and leave");
       } catch (InterruptedException e) {<!-- -->
        e.printStackTrace();
       }
     }
}
class Programmer{<!-- -->
  private String name;
  public Programmer(String name){<!-- -->
    this.name = name;
   }
  /**
   * turn on computer
   */
  synchronized public void computer(){<!-- -->
      try {<!-- -->
        System.out.println(this.name + "Power on");
        Thread.sleep(500);
        System.out.println(this.name + "Press the power button");
        Thread.sleep(500);
        System.out.println(this.name + "System is starting");
        Thread.sleep(500);
        System.out.println(this.name + "System startup successful");
       } catch (InterruptedException e) {<!-- -->
        e.printStackTrace();
       }
   }
  /**
   * encoding
   */
  synchronized public void coding(){<!-- -->
      try {<!-- -->
        System.out.println(this.name + "Double-click Idea");
        Thread.sleep(500);
        System.out.println(this.name + "Idea startup completed");
        Thread.sleep(500);
        System.out.println(this.name + "Write code happily");
       } catch (InterruptedException e) {<!-- -->
        e.printStackTrace();
       }
     }
  /**
   * Go to the bathroom
   */
  public void wc(){<!-- -->
    synchronized ("suibian") {<!-- -->
      try {<!-- -->
        System.out.println(this.name + "Open the bathroom door");
        Thread.sleep(500);
        System.out.println(this.name + "Start excreting");
        Thread.sleep(500);
        System.out.println(this.name + "flush");
        Thread.sleep(500);
        System.out.println(this.name + "Leave the bathroom");
       } catch (InterruptedException e) {<!-- -->
        e.printStackTrace();
       }
     }
   }
  /**
   * Claim your bonus
   */
  public void money(){<!-- -->
    synchronized (Programmer.class) {<!-- -->
      try {<!-- -->
        System.out.println(this.name + "Praised by the leader");
        Thread.sleep(500);
        System.out.println(this.name + "Get money");
        Thread.sleep(500);
        System.out.println(this.name + "Thank you to the company");
        Thread.sleep(500);
        System.out.println(this.name + "Take the money and leave happily");
       } catch (InterruptedException e) {<!-- -->
        e.printStackTrace();
       }
     }
   }
}


/**
 * Open the computer's working thread
 */
class Working1 extends Thread{<!-- -->
  private Programmer p;
  public Working1(Programmer p){<!-- -->
    this.p = p;
   }
  @Override
  public void run() {<!-- -->
    this.p.computer();
   }
}


/**
 * Worker thread for writing code
 */
class Working2 extends Thread{<!-- -->
  private Programmer p;
  public Working2(Programmer p){<!-- -->
    this.p = p;
   }
  @Override
  public void run() {<!-- -->
    this.p.coding();
   }
}


/**
 * Thread to go to the bathroom
 */
class WC extends Thread{<!-- -->
  private Programmer p;
  public WC(Programmer p){<!-- -->
    this.p = p;
   }
  @Override
  public void run() {<!-- -->
    this.p.wc();
   }
}


/**
 * Programmers receive bonuses
 */
class ProgrammerMoney extends Thread{<!-- -->
  private Programmer p;
  public ProgrammerMoney(Programmer p){<!-- -->
    this.p = p;
   }
  @Override
  public void run() {<!-- -->
    this.p.money();
   }
}


/**
 * Sales department receives bonus
 */
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("Zhang San");
    Programmer p1 = new Programmer("李思");
    new ProgrammerMoney(p).start();
    new ProgrammerMoney(p1).start();*/
    
    Sale s = new Sale("Zhang Xiaoli");
    Sale s1 = new Sale("Wang Xiaohong");
    new SaleMoney(s).start();
    new SaleMoney(s1).start();
   }
}

Use custom objects as thread object locks

Grammatical structures:

synchronized(custom object){<!-- -->
//Synchronization code
}

/**
 * Define sales employee class
 */
class Sale{<!-- -->
  private String name;
  public Sale(String name){<!-- -->
    this.name = name;
   }
  /**
   * Claim your bonus
   */
  synchronized public static void money(){<!-- -->
      try {<!-- -->
        System.out.println(Thread.currentThread().getName() + "Praised by the leader");
        Thread.sleep(500);
        System.out.println(Thread.currentThread().getName() + "Get money");
        Thread.sleep(500);
        System.out.println(Thread.currentThread().getName() + "Thank you to the company");
        Thread.sleep(500);
        System.out.println(Thread.currentThread().getName() + "Happily take the money and leave");
       } catch (InterruptedException e) {<!-- -->
        e.printStackTrace();
       }
     }
}
class Programmer{<!-- -->
  private String name;
  public Programmer(String name){<!-- -->
    this.name = name;
   }
  /**
   * turn on computer
   */
  synchronized public void computer(){<!-- -->
      try {<!-- -->
        System.out.println(this.name + "Power on");
        Thread.sleep(500);
        System.out.println(this.name + "Press the power button");
        Thread.sleep(500);
        System.out.println(this.name + "System is starting");
        Thread.sleep(500);
        System.out.println(this.name + "System startup successful");
       } catch (InterruptedException e) {<!-- -->
        e.printStackTrace();
       }
   }
  /**
   * encoding
   */
  synchronized public void coding(){<!-- -->
      try {<!-- -->
        System.out.println(this.name + "Double-click Idea");
        Thread.sleep(500);
        System.out.println(this.name + "Idea startup completed");
        Thread.sleep(500);
        System.out.println(this.name + "Write code happily");
       } catch (InterruptedException e) {<!-- -->
        e.printStackTrace();
       }
     }
  /**
   * Go to the bathroom
   */
  public void wc(){<!-- -->
    synchronized ("suibian") {<!-- -->
      try {<!-- -->
        System.out.println(this.name + "Open the bathroom door");
        Thread.sleep(500);
        System.out.println(this.name + "Start excreting");
        Thread.sleep(500);
        System.out.println(this.name + "flush");
        Thread.sleep(500);
        System.out.println(this.name + "Leave the bathroom");
       } catch (InterruptedException e) {<!-- -->
        e.printStackTrace();
       }
     }
   }
  /**
   * Claim your bonus
   */
  public void money(){<!-- -->
    synchronized (Programmer.class) {<!-- -->
      try {<!-- -->
        System.out.println(this.name + "Praised by the leader");
        Thread.sleep(500);
        System.out.println(this.name + "Get money");
        Thread.sleep(500);
        System.out.println(this.name + "Thank you to the company");
        Thread.sleep(500);
        System.out.println(this.name + "Take the money and leave happily");
       } catch (InterruptedException e) {<!-- -->
        e.printStackTrace();
       }
     }
   }
}
class Manager{<!-- -->
  private String name;
  public Manager(String name){<!-- -->
    this.name = name;
   }
  public String getName(){<!-- -->
    return this.name;
   }
  /**
   * Toast
   */
  public void cheers(String mName,String eName){<!-- -->
      try {<!-- -->
        System.out.println(mName + "Come to " + eName + "");
        Thread.sleep(500);
        System.out.println(eName + "Pick up the wine glass");
        Thread.sleep(500);
        System.out.println(mName + " and " + eName + "Cheers");
       } catch (InterruptedException e) {<!-- -->
        e.printStackTrace();
       }
   }
}
/**
 * Open the computer's working thread
 */
class Working1 extends Thread{<!-- -->
  private Programmer p;
  public Working1(Programmer p){<!-- -->
    this.p = p;
   }
  @Override
  public void run() {<!-- -->
    this.p.computer();
   }
}


/**
 * Worker thread for writing code
 */
class Working2 extends Thread{<!-- -->
  private Programmer p;
  public Working2(Programmer p){<!-- -->
    this.p = p;
   }
  @Override
  public void run() {<!-- -->
    this.p.coding();
   }
}


/**
 * Thread to go to the bathroom
 */
class WC extends Thread{<!-- -->
  private Programmer p;
  public WC(Programmer p){<!-- -->
    this.p = p;
   }
  @Override
  public void run() {<!-- -->
    this.p.wc();
   }
}


/**
 * Programmers receive bonuses
 */
class ProgrammerMoney extends Thread{<!-- -->
  private Programmer p;
  public ProgrammerMoney(Programmer p){<!-- -->
    this.p = p;
   }
  @Override
  public void run() {<!-- -->
    this.p.money();
   }
}


/**
 * Sales department receives bonus
 */
class SaleMoneyThread extends Thread{<!-- -->
  private Sale p;
  public SaleMoneyThread(Sale p){<!-- -->
    this.p = p;
   }
  @Override
  public void run() {<!-- -->
    this.p.money();
   }
}


/**
 * Toast thread class
 */
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("Zhang Sanfeng");
    new CheersThread("Zhang San",manager).start();
    new CheersThread("李思",manager).start();


   }
}

Deadlock and solution

The concept of deadlock

“Deadlock” refers to:

Multiple threads each occupy some shared resources, and each waits for the resources occupied by other threads to proceed, resulting in a situation where two or more threads are waiting for each other to release resources and both stop execution.

When a synchronized block needs to hold “locks on more than two objects” at the same time, a “deadlock” problem may occur. For example, the “makeup thread” needs to own both the “mirror object” and the “lipstick object” to run the synchronization block. Then, when it is actually running, “Xiaoya’s makeup thread” owns the “mirror object” and “Daya’s makeup thread” owns the “lipstick object”, and they are both waiting for each other to release resources before they can put on makeup. In this way, the two threads form a “deadlock state” where they wait for each other and cannot continue to run.

Deadlock case demonstration

/**
 * Lipstick category
 */
class Lipstick{<!-- -->


}


/**
 *Mirrors
 */
class Mirror{<!-- -->


}


/**
 * Makeup thread category
 */
class Makeup extends Thread{<!-- -->
  private int flag; //flag=0: Hold the lipstick. flag!=0: Hold the mirror
  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();
   }
  /**
   * Start putting on makeup
   */
  public void doMakeup(){<!-- -->
    if(flag == 0){<!-- -->
      synchronized (lipstick){<!-- -->
        System.out.println(this.girlName + "Holding lipstick");
        try {<!-- -->
          Thread.sleep(1000);
         } catch (InterruptedException e) {<!-- -->
          e.printStackTrace();
         }
        synchronized (mirror){<!-- -->
          System.out.println(this.girlName + "Holding a mirror");
         }
       }
     }else{<!-- -->
      synchronized (mirror){<!-- -->
        System.out.println(this.girlName + "Holding a mirror");
        try {<!-- -->
          Thread.sleep(2000);
         } catch (InterruptedException e) {<!-- -->
          e.printStackTrace();
         }
        synchronized (lipstick){<!-- -->
          System.out.println(this.girlName + "Holding lipstick");
         }
       }
     }
   }
}


public class DeadLockThread {<!-- -->
  public static void main(String[] args) {<!-- -->
    new Makeup(0,"大aya").start();
    new Makeup(1,"Xiaoya").start();
   }
}

Solution to deadlock problem

Deadlock is caused by “synchronized blocks need to hold multiple object locks at the same time.” To solve this problem, the idea is very simple: do not hold two object locks at the same time for the same code block.

/**
 * Lipstick category
 */
class Lipstick{<!-- -->


}


/**
 *Mirrors
 */
class Mirror{<!-- -->


}


/**
 * Makeup thread category
 */
class Makeup extends Thread{<!-- -->
  private int flag; //flag=0: Hold the lipstick. flag!=0: Hold the mirror
  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();
   }
  /**
   * Start putting on makeup
   */
  public void doMakeup(){<!-- -->
    if(flag == 0){<!-- -->
      synchronized (lipstick){<!-- -->
        System.out.println(this.girlName + "Holding lipstick");
        try {<!-- -->
          Thread.sleep(1000);
         } catch (InterruptedException e) {<!-- -->
          e.printStackTrace();
         }
       }
      synchronized (mirror){<!-- -->
        System.out.println(this.girlName + "Holding a mirror");
       }
     }else{<!-- -->
      synchronized (mirror){<!-- -->
        System.out.println(this.girlName + "Holding a mirror");
        try {<!-- -->
          Thread.sleep(2000);
         } catch (InterruptedException e) {<!-- -->
          e.printStackTrace();
         }
       }
      synchronized (lipstick){<!-- -->
        System.out.println(this.girlName + "Holding lipstick");
       }
     }
   }
}


public class DeadLockThread {<!-- -->
  public static void main(String[] args) {<!-- -->
    Makeup makeup = new Makeup();
    makeup.setFlag(0);
    makeup.setGirlName("大aya");
    Makeup makeup1 = new Makeup();
    makeup1.setFlag(1);
    makeup1.setGirlName("Xiaoya");
    makeup.start();
    makeup1.start();
   }
}