JAVA多线程同步代码块

一、简介

1.什么情况下需要同步

当多线程并发,有多段代码同时执行时,我们希望某一段代码执行的过程中CPU不要切换到其他线程工作,这时就需要同步

如果两段代码是同步的,那么同一时间只能执行一段,在一段代码没执行结束之前,不会执行另外一段代码

2.同步代码块

使用synchronized关键字加上一个锁对象来定义一段代码,这就叫同步代码块

多个同步代码块如果使用相同的锁对象,那么他们就是同步的

class Printer {
   Demo d = new Demo();
   public void print1() {
      //synchronized(new Demo()) {                     //同步代码块,锁机制,锁对象可以是任意的
      synchronized(d) {
         System.out.print("1");
         System.out.print("2");
         System.out.print("3");
         System.out.print("4");
         System.out.print("5");
         System.out.print("\r\n");
      }
   }
   
   public void print2() {
      //synchronized(new Demo()) {                     //锁对象不能用匿名对象,因为匿名对象不是同一个对象
      synchronized(d) {     
         System.out.print("a");
         System.out.print("b");
         System.out.print("c");
         System.out.print("d");
         System.out.print("\r\n");
      }
   }
}

 使用synchronized关键字修饰一个方法,该方法中所有的代码都是同步的

  • 非静态的同步方法的锁对象:this
  • 静态的同步方法的锁对象:该类的字节码对象
class Printer2 {
   public static synchronized void print1() {         //同步方法只需要在方法上加synchronized关键字即可
      System.out.print("1");
      System.out.print("2");
      System.out.print("3");
      System.out.print("4");
      System.out.print("5");
      System.out.print("\r\n");
   }
   
   public static void print2() {
      synchronized(Printer2.class) {    
         System.out.print("a");
         System.out.print("b");
         System.out.print("c");
         System.out.print("d");
         System.out.print("\r\n");
      }
   }
}

二、线程安全问题

多线程并发操作同一数据时,就有可能出现线程安全问题

使用同步技术可以解决这种问题,把操作数据的代码进行同步,不要多个线程一起操作

案例:火车站售票

public class Demo3 {
   /**
    * 需求:铁路售票,一共100张,通过四个窗口卖完.
    */
   public static void main(String[] args) {
      new Ticket().start();
      new Ticket().start();
      new Ticket().start();
      new Ticket().start();
   }

}

class Ticket extends Thread {
   private static int ticket = 100;
   //private static Object obj = new Object();       //如果用引用数据类型成员变量当作锁对象,必须是静态的
   public void run() {
      while(true) {
         synchronized(Ticket.class) {
            if(ticket <= 0) {
               break;
            }
            try {
               Thread.sleep(10);           
            } catch (InterruptedException e) {
               
               e.printStackTrace();
            }
            System.out.println(getName() + "...这是第" + ticket-- + "号票");
         }
      }
   }
}
public class Demo4_Ticket {
   /**
    * @param args
    * 火车站卖票的例子用实现Runnable接口
    */
   public static void main(String[] args) {
      MyTicket mt = new MyTicket();
      new Thread(mt).start();
      new Thread(mt).start();
      new Thread(mt).start();
      new Thread(mt).start();
   }

}

class MyTicket implements Runnable {
   private int tickets = 100;
   @Override
   public void run() {
      while(true) {
         synchronized(this) {
            if(tickets <= 0) {
               break;
            }
            try {
               Thread.sleep(10);          
            } catch (InterruptedException e) {               
               e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "...这是第" + tickets-- + "号票");
         }
      }
   }
}

多线程同步的时候,如果同步代码嵌套,使用相同锁,就有可能出现死锁;尽量不要嵌套使用。

public class Demo5_DeadLock {
   private static String s1 = "筷子左";
   private static String s2 = "筷子右";

   public static void main(String[] args) {
      new Thread() {
         public void run() {
            while(true) {
               synchronized(s1) {
                  System.out.println(getName() + "...获取" + s1 + "等待" + s2);
                  synchronized(s2) {
                     System.out.println(getName() + "...拿到" + s2 + "开吃");
                  }
               }
            }
         }
      }.start();
      
      new Thread() {
         public void run() {
            while(true) {
               synchronized(s2) {
                  System.out.println(getName() + "...获取" + s2 + "等待" + s1);
                  synchronized(s1) {
                     System.out.println(getName() + "...拿到" + s1 + "开吃");
                  }
               }
            }
         }
      }.start();
   }
}

猜你喜欢

转载自blog.csdn.net/qq_40298054/article/details/87901149