Java基础复习 Day 20

Java基础复习 Day 20

多线程(3)

  1. 多线程出现安全问题

    当多线程访问(有写操作,更改共享数据的值的时候)共享数据的时候,会产生线程安全问题

    以卖票案例为例做代码实现:(三个窗口同时卖100张1-100号的票,就会出现安全问题,同一张票可能会被卖多次,或者出现没有票了却还在被卖。。)

//创建Runnable接口的实现类,定义共享数据
/*
* 实现卖票案例
* */
public class RunnableImpl implements Runnable{
    private int ticket = 100;
    @Override
    public void run() {
        while (true){
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (ticket>0) {
                System.out.println(Thread.currentThread().getName()+" 正在卖第: "+ ticket +"张票");
                ticket--;
            }
        }
    }
}
//定义三个线程去访问这个共享数据
/*
* 创建三个线程让这三个线程都对共享的票进行出售
* 共享体现在只有一个runnable的实现类,但是用三个线程来执行
* */
public class DemoMain {
    public static void main(String[] args) {
        RunnableImpl run = new RunnableImpl();
        Thread t1 = new Thread(run);
        Thread t2 = new Thread(run);
        Thread t3 = new Thread(run);
        t1.start();
        t2.start();
        t3.start();
    }
}

打印结果

Thread-2 正在卖第: 100张票
Thread-0 正在卖第: 100张票
Thread-1 正在卖第: 100张票
Thread-1 正在卖第: 97张票
Thread-0 正在卖第: 97张票
Thread-2 正在卖第: 97张票
Thread-2 正在卖第: 94张票
Thread-1 正在卖第: 94张票
Thread-0 正在卖第: 94张票
Thread-0 正在卖第: 91张票
Thread-2 正在卖第: 91张票
Thread-1 正在卖第: 91张票
Thread-1 正在卖第: 88张票
Thread-2 正在卖第: 88张票
Thread-0 正在卖第: 88张票
Thread-2 正在卖第: 85张票
Thread-0 正在卖第: 85张票
Thread-1 正在卖第: 85张票
Thread-1 正在卖第: 82张票
Thread-2 正在卖第: 82张票
Thread-0 正在卖第: 82张票
Thread-2 正在卖第: 79张票
Thread-1 正在卖第: 79张票
Thread-0 正在卖第: 79张票
Thread-1 正在卖第: 76张票
Thread-0 正在卖第: 76张票
Thread-2 正在卖第: 76张票
Thread-2 正在卖第: 73张票
Thread-0 正在卖第: 73张票
Thread-1 正在卖第: 73张票
Thread-2 正在卖第: 70张票
Thread-0 正在卖第: 70张票
Thread-1 正在卖第: 70张票
Thread-1 正在卖第: 67张票
Thread-0 正在卖第: 67张票
Thread-2 正在卖第: 67张票
Thread-0 正在卖第: 64张票
Thread-2 正在卖第: 64张票
Thread-1 正在卖第: 64张票
Thread-0 正在卖第: 61张票
Thread-1 正在卖第: 61张票
Thread-2 正在卖第: 61张票
Thread-1 正在卖第: 58张票
Thread-0 正在卖第: 58张票
Thread-2 正在卖第: 58张票
Thread-0 正在卖第: 55张票
Thread-2 正在卖第: 54张票
Thread-1 正在卖第: 54张票
Thread-2 正在卖第: 52张票
Thread-1 正在卖第: 52张票
Thread-0 正在卖第: 52张票
Thread-2 正在卖第: 49张票
Thread-1 正在卖第: 49张票
Thread-0 正在卖第: 48张票
Thread-1 正在卖第: 46张票
Thread-2 正在卖第: 45张票
Thread-0 正在卖第: 46张票
Thread-0 正在卖第: 43张票
Thread-2 正在卖第: 43张票
Thread-1 正在卖第: 43张票
Thread-1 正在卖第: 40张票
Thread-2 正在卖第: 40张票
Thread-0 正在卖第: 40张票
Thread-0 正在卖第: 37张票
Thread-2 正在卖第: 37张票
Thread-1 正在卖第: 37张票
Thread-1 正在卖第: 34张票
Thread-0 正在卖第: 33张票
Thread-2 正在卖第: 32张票
Thread-1 正在卖第: 31张票
Thread-0 正在卖第: 31张票
Thread-2 正在卖第: 30张票
Thread-2 正在卖第: 28张票
Thread-1 正在卖第: 28张票
Thread-0 正在卖第: 28张票
Thread-0 正在卖第: 25张票
Thread-2 正在卖第: 25张票
Thread-1 正在卖第: 25张票
Thread-2 正在卖第: 22张票
Thread-1 正在卖第: 22张票
Thread-0 正在卖第: 22张票
Thread-1 正在卖第: 19张票
Thread-0 正在卖第: 19张票
Thread-2 正在卖第: 19张票
Thread-2 正在卖第: 16张票
Thread-1 正在卖第: 16张票
Thread-0 正在卖第: 16张票
Thread-0 正在卖第: 13张票
Thread-1 正在卖第: 13张票
Thread-2 正在卖第: 13张票
Thread-2 正在卖第: 10张票
Thread-1 正在卖第: 9张票
Thread-0 正在卖第: 9张票
Thread-2 正在卖第: 7张票
Thread-1 正在卖第: 7张票
Thread-0 正在卖第: 7张票
Thread-0 正在卖第: 4张票
Thread-2 正在卖第: 4张票
Thread-1 正在卖第: 3张票
Thread-2 正在卖第: 1张票
Thread-0 正在卖第: 1张票
Thread-1 正在卖第: 1张票
  1. 多线程安全问题的解决

    多线程的同步来解决线程安全问题,多线程的同步可以有以下三种实现方式:

    • 同步代码块
    • 同步方法
    • 锁机制

    ①同步代码块:synchronized关键字可以用于方法中的某个区块中,表示只对这个区块的资源进行互斥访问

    格式:

    synchronized(同步锁){

    需要同步操作的代码

    }

    同步锁:对象的同步锁只是一个概念,可以想象为在对象上标记了一个锁

    1. 锁对象可以是任一类型

    2. 多个线程对象,要使用同一把锁

      注意:多个线程在任何时候,都最多允许只有一个线程拿到这个同步锁,谁拿到同步锁谁就进入代码块,其他线程则必须等待(BLOCKED)

      //在重写runnalbe的类中加入一个object(任一)的锁对象,同时在重写run方法时,在其中修改共享数据的语句包裹在synchronizede中
      /*
      * 同步代码块解决实现卖票案例中出现的线程安全问题
      * */
      public class RunnableImpl implements Runnable{
          private int ticket = 100;
          //创建一个锁对象
          Object object = new Object();
          @Override
          public void run() {
              while (true){
                  synchronized (object){
                      try {
                          Thread.sleep(10);
                      } catch (InterruptedException e) {
                          e.printStackTrace();
                      }
                      if (ticket>0) {
                          System.out.println(Thread.currentThread().getName()+" 正在卖第: "+ ticket +"张票");
                          ticket--;
                      }
                  }
              }
          }
      }
      //主方法不变,继续让三个线程来执行这个run方法
      /*
      * 创建三个线程让这三个线程都对共享的票进行出售
      * 共享体现在只有一个runnable的实现类,但是用三个线程来执行
      * */
      public class DemoMain {
          public static void main(String[] args) {
              RunnableImpl run = new RunnableImpl();
              Thread t1 = new Thread(run);
              Thread t2 = new Thread(run);
              Thread t3 = new Thread(run);
              t1.start();
              t2.start();
              t3.start();
      
          }
      }
      

      打印结果能看到,解决了线程安全问题:

      Thread-0 正在卖第: 100张票
      Thread-0 正在卖第: 99张票
      Thread-0 正在卖第: 98张票
      Thread-0 正在卖第: 97张票
      Thread-0 正在卖第: 96张票
      Thread-0 正在卖第: 95张票
      Thread-0 正在卖第: 94张票
      Thread-0 正在卖第: 93张票
      Thread-0 正在卖第: 92张票
      Thread-0 正在卖第: 91张票
      Thread-0 正在卖第: 90张票
      Thread-0 正在卖第: 89张票
      Thread-0 正在卖第: 88张票
      Thread-0 正在卖第: 87张票
      Thread-0 正在卖第: 86张票
      Thread-0 正在卖第: 85张票
      Thread-0 正在卖第: 84张票
      Thread-0 正在卖第: 83张票
      Thread-0 正在卖第: 82张票
      Thread-0 正在卖第: 81张票
      Thread-0 正在卖第: 80张票
      Thread-0 正在卖第: 79张票
      Thread-0 正在卖第: 78张票
      Thread-0 正在卖第: 77张票
      Thread-0 正在卖第: 76张票
      Thread-0 正在卖第: 75张票
      Thread-0 正在卖第: 74张票
      Thread-0 正在卖第: 73张票
      Thread-0 正在卖第: 72张票
      Thread-0 正在卖第: 71张票
      Thread-0 正在卖第: 70张票
      Thread-0 正在卖第: 69张票
      Thread-0 正在卖第: 68张票
      Thread-0 正在卖第: 67张票
      Thread-0 正在卖第: 66张票
      Thread-0 正在卖第: 65张票
      Thread-0 正在卖第: 64张票
      Thread-0 正在卖第: 63张票
      Thread-0 正在卖第: 62张票
      Thread-0 正在卖第: 61张票
      Thread-0 正在卖第: 60张票
      Thread-0 正在卖第: 59张票
      Thread-1 正在卖第: 58张票
      Thread-1 正在卖第: 57张票
      Thread-1 正在卖第: 56张票
      Thread-1 正在卖第: 55张票
      Thread-1 正在卖第: 54张票
      Thread-1 正在卖第: 53张票
      Thread-1 正在卖第: 52张票
      Thread-1 正在卖第: 51张票
      Thread-2 正在卖第: 50张票
      Thread-2 正在卖第: 49张票
      Thread-2 正在卖第: 48张票
      Thread-2 正在卖第: 47张票
      Thread-2 正在卖第: 46张票
      Thread-2 正在卖第: 45张票
      Thread-2 正在卖第: 44张票
      Thread-2 正在卖第: 43张票
      Thread-2 正在卖第: 42张票
      Thread-2 正在卖第: 41张票
      Thread-2 正在卖第: 40张票
      Thread-2 正在卖第: 39张票
      Thread-2 正在卖第: 38张票
      Thread-2 正在卖第: 37张票
      Thread-2 正在卖第: 36张票
      Thread-2 正在卖第: 35张票
      Thread-2 正在卖第: 34张票
      Thread-2 正在卖第: 33张票
      Thread-2 正在卖第: 32张票
      Thread-2 正在卖第: 31张票
      Thread-2 正在卖第: 30张票
      Thread-2 正在卖第: 29张票
      Thread-2 正在卖第: 28张票
      Thread-2 正在卖第: 27张票
      Thread-2 正在卖第: 26张票
      Thread-2 正在卖第: 25张票
      Thread-2 正在卖第: 24张票
      Thread-2 正在卖第: 23张票
      Thread-1 正在卖第: 22张票
      Thread-1 正在卖第: 21张票
      Thread-1 正在卖第: 20张票
      Thread-1 正在卖第: 19张票
      Thread-1 正在卖第: 18张票
      Thread-1 正在卖第: 17张票
      Thread-1 正在卖第: 16张票
      Thread-1 正在卖第: 15张票
      Thread-1 正在卖第: 14张票
      Thread-1 正在卖第: 13张票
      Thread-1 正在卖第: 12张票
      Thread-1 正在卖第: 11张票
      Thread-1 正在卖第: 10张票
      Thread-1 正在卖第: 9张票
      Thread-1 正在卖第: 8张票
      Thread-1 正在卖第: 7张票
      Thread-1 正在卖第: 6张票
      Thread-1 正在卖第: 5张票
      Thread-1 正在卖第: 4张票
      Thread-1 正在卖第: 3张票
      Thread-1 正在卖第: 2张票
      Thread-1 正在卖第: 1张票
      
      

      同步代码块原理

    在这里插入图片描述

    ②同步方法:使用synchronized修饰的方法就叫做,同步方法,保证线程A在使用该方法的时候,其他方法只能在方法外等待

    格式:

    修饰符 synchronized 返回值类型 方法名(参数列表){

    ​ //可能会产生线程安全问题的代码

    }

    同步锁:

    在同步非静态方法中,同步锁就是this

    在静态方法中,同步锁就是类的字节码对象(类名.class)

    //在Runnable的实现类中,重新定义一个非静态同步方法,把可能产生线程安全问题的代码写入该方法中
    //在run方法中去调用该同步方法、
    /*
    * 同步方法结局卖票案例中的线程安全问题
    * */
    public class RunnableImpl implements Runnable{
        private int ticket = 100;
        @Override
        public void run() {
            while (true){
                sellTicket();
            }
        }
        public synchronized void sellTicket(){
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (ticket>0) {
                System.out.println(Thread.currentThread().getName()+" 正在卖第: "+ ticket +"张票");
                ticket--;
            }
        }
    }
    //主方法不变,三个线程去调用run方法
    //在同步非静态方法中,同步锁就是this 在这个例子中就是new的对象run
    /*
    * 创建三个线程让这三个线程都对共享的票进行出售
    * 共享体现在只有一个runnable的实现类,但是用三个线程来执行
    * */
    public class DemoMain {
        public static void main(String[] args) {
            RunnableImpl run = new RunnableImpl();
            Thread t1 = new Thread(run);
            Thread t2 = new Thread(run);
            Thread t3 = new Thread(run);
            t1.start();
            t2.start();
            t3.start();
    
        }
    }
    

    打印结果:解决线程安全问题

    Thread-0 正在卖第: 100张票
    Thread-0 正在卖第: 99张票
    Thread-0 正在卖第: 98张票
    Thread-0 正在卖第: 97张票
    Thread-0 正在卖第: 96张票
    Thread-0 正在卖第: 95张票
    Thread-0 正在卖第: 94张票
    Thread-0 正在卖第: 93张票
    Thread-0 正在卖第: 92张票
    Thread-0 正在卖第: 91张票
    Thread-0 正在卖第: 90张票
    Thread-0 正在卖第: 89张票
    Thread-0 正在卖第: 88张票
    Thread-0 正在卖第: 87张票
    Thread-0 正在卖第: 86张票
    Thread-0 正在卖第: 85张票
    Thread-0 正在卖第: 84张票
    Thread-0 正在卖第: 83张票
    Thread-2 正在卖第: 82张票
    Thread-2 正在卖第: 81张票
    Thread-2 正在卖第: 80张票
    Thread-2 正在卖第: 79张票
    Thread-2 正在卖第: 78张票
    Thread-2 正在卖第: 77张票
    Thread-2 正在卖第: 76张票
    Thread-2 正在卖第: 75张票
    Thread-2 正在卖第: 74张票
    Thread-2 正在卖第: 73张票
    Thread-2 正在卖第: 72张票
    Thread-2 正在卖第: 71张票
    Thread-2 正在卖第: 70张票
    Thread-2 正在卖第: 69张票
    Thread-2 正在卖第: 68张票
    Thread-2 正在卖第: 67张票
    Thread-2 正在卖第: 66张票
    Thread-1 正在卖第: 65张票
    Thread-1 正在卖第: 64张票
    Thread-1 正在卖第: 63张票
    Thread-1 正在卖第: 62张票
    Thread-1 正在卖第: 61张票
    Thread-1 正在卖第: 60张票
    Thread-1 正在卖第: 59张票
    Thread-1 正在卖第: 58张票
    Thread-1 正在卖第: 57张票
    Thread-1 正在卖第: 56张票
    Thread-1 正在卖第: 55张票
    Thread-1 正在卖第: 54张票
    Thread-1 正在卖第: 53张票
    Thread-1 正在卖第: 52张票
    Thread-1 正在卖第: 51张票
    Thread-1 正在卖第: 50张票
    Thread-1 正在卖第: 49张票
    Thread-1 正在卖第: 48张票
    Thread-1 正在卖第: 47张票
    Thread-1 正在卖第: 46张票
    Thread-1 正在卖第: 45张票
    Thread-1 正在卖第: 44张票
    Thread-1 正在卖第: 43张票
    Thread-1 正在卖第: 42张票
    Thread-1 正在卖第: 41张票
    Thread-1 正在卖第: 40张票
    Thread-1 正在卖第: 39张票
    Thread-1 正在卖第: 38张票
    Thread-1 正在卖第: 37张票
    Thread-1 正在卖第: 36张票
    Thread-1 正在卖第: 35张票
    Thread-1 正在卖第: 34张票
    Thread-1 正在卖第: 33张票
    Thread-1 正在卖第: 32张票
    Thread-1 正在卖第: 31张票
    Thread-1 正在卖第: 30张票
    Thread-1 正在卖第: 29张票
    Thread-2 正在卖第: 28张票
    Thread-2 正在卖第: 27张票
    Thread-2 正在卖第: 26张票
    Thread-2 正在卖第: 25张票
    Thread-2 正在卖第: 24张票
    Thread-2 正在卖第: 23张票
    Thread-2 正在卖第: 22张票
    Thread-2 正在卖第: 21张票
    Thread-2 正在卖第: 20张票
    Thread-2 正在卖第: 19张票
    Thread-2 正在卖第: 18张票
    Thread-2 正在卖第: 17张票
    Thread-2 正在卖第: 16张票
    Thread-0 正在卖第: 15张票
    Thread-0 正在卖第: 14张票
    Thread-0 正在卖第: 13张票
    Thread-0 正在卖第: 12张票
    Thread-0 正在卖第: 11张票
    Thread-0 正在卖第: 10张票
    Thread-0 正在卖第: 9张票
    Thread-0 正在卖第: 8张票
    Thread-0 正在卖第: 7张票
    Thread-0 正在卖第: 6张票
    Thread-0 正在卖第: 5张票
    Thread-0 正在卖第: 4张票
    Thread-0 正在卖第: 3张票
    Thread-0 正在卖第: 2张票
    Thread-0 正在卖第: 1张票
    

    静态同步方法:

    //在Runnable的实现类中,重新定义一个静态同步方法,把可能产生线程安全问题的代码写入该方法中
    //在run方法中去调用该同步方法、
    /*
    * 同步方法结局卖票案例中的线程安全问题
    * */
    public class RunnableImpl implements Runnable{
        private static int ticket = 100;
        @Override
        public void run() {
            while (true){
                sellTicketStatic();
            }
        }
        public static synchronized void sellTicketStatic(){
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (ticket>0) {
                System.out.println(Thread.currentThread().getName()+" 正在卖第: "+ ticket +"张票");
                ticket--;
            }
        }
    
    }
    //主方法开启三个线程去执行run方法
    /*
    * 创建三个线程让这三个线程都对共享的票进行出售
    * 共享体现在只有一个runnable的实现类,但是用三个线程来执行
    此时静态方法的锁对象就是 Runnable.class
    * */
    public class DemoMain {
        public static void main(String[] args) {
            RunnableImpl run = new RunnableImpl();
            Thread t1 = new Thread(run);
            Thread t2 = new Thread(run);
            Thread t3 = new Thread(run);
            t1.start();
            t2.start();
            t3.start();
    
        }
    }
    

    打印结果:依然是解决了线程安全问题

    Thread-0 正在卖第: 100张票
    Thread-0 正在卖第: 99张票
    Thread-0 正在卖第: 98张票
    Thread-0 正在卖第: 97张票
    Thread-0 正在卖第: 96张票
    Thread-0 正在卖第: 95张票
    Thread-0 正在卖第: 94张票
    Thread-2 正在卖第: 93张票
    Thread-2 正在卖第: 92张票
    Thread-2 正在卖第: 91张票
    Thread-2 正在卖第: 90张票
    Thread-2 正在卖第: 89张票
    Thread-2 正在卖第: 88张票
    Thread-2 正在卖第: 87张票
    Thread-2 正在卖第: 86张票
    Thread-2 正在卖第: 85张票
    Thread-2 正在卖第: 84张票
    Thread-2 正在卖第: 83张票
    Thread-2 正在卖第: 82张票
    Thread-2 正在卖第: 81张票
    Thread-2 正在卖第: 80张票
    Thread-2 正在卖第: 79张票
    Thread-2 正在卖第: 78张票
    Thread-2 正在卖第: 77张票
    Thread-2 正在卖第: 76张票
    Thread-2 正在卖第: 75张票
    Thread-2 正在卖第: 74张票
    Thread-2 正在卖第: 73张票
    Thread-2 正在卖第: 72张票
    Thread-2 正在卖第: 71张票
    Thread-1 正在卖第: 70张票
    Thread-1 正在卖第: 69张票
    Thread-1 正在卖第: 68张票
    Thread-1 正在卖第: 67张票
    Thread-1 正在卖第: 66张票
    Thread-1 正在卖第: 65张票
    Thread-1 正在卖第: 64张票
    Thread-1 正在卖第: 63张票
    Thread-1 正在卖第: 62张票
    Thread-1 正在卖第: 61张票
    Thread-1 正在卖第: 60张票
    Thread-1 正在卖第: 59张票
    Thread-1 正在卖第: 58张票
    Thread-1 正在卖第: 57张票
    Thread-2 正在卖第: 56张票
    Thread-2 正在卖第: 55张票
    Thread-2 正在卖第: 54张票
    Thread-0 正在卖第: 53张票
    Thread-0 正在卖第: 52张票
    Thread-0 正在卖第: 51张票
    Thread-0 正在卖第: 50张票
    Thread-0 正在卖第: 49张票
    Thread-0 正在卖第: 48张票
    Thread-0 正在卖第: 47张票
    Thread-0 正在卖第: 46张票
    Thread-0 正在卖第: 45张票
    Thread-0 正在卖第: 44张票
    Thread-0 正在卖第: 43张票
    Thread-0 正在卖第: 42张票
    Thread-0 正在卖第: 41张票
    Thread-0 正在卖第: 40张票
    Thread-0 正在卖第: 39张票
    Thread-0 正在卖第: 38张票
    Thread-0 正在卖第: 37张票
    Thread-0 正在卖第: 36张票
    Thread-0 正在卖第: 35张票
    Thread-0 正在卖第: 34张票
    Thread-0 正在卖第: 33张票
    Thread-0 正在卖第: 32张票
    Thread-0 正在卖第: 31张票
    Thread-2 正在卖第: 30张票
    Thread-2 正在卖第: 29张票
    Thread-2 正在卖第: 28张票
    Thread-2 正在卖第: 27张票
    Thread-1 正在卖第: 26张票
    Thread-1 正在卖第: 25张票
    Thread-1 正在卖第: 24张票
    Thread-1 正在卖第: 23张票
    Thread-1 正在卖第: 22张票
    Thread-1 正在卖第: 21张票
    Thread-1 正在卖第: 20张票
    Thread-1 正在卖第: 19张票
    Thread-1 正在卖第: 18张票
    Thread-1 正在卖第: 17张票
    Thread-1 正在卖第: 16张票
    Thread-1 正在卖第: 15张票
    Thread-1 正在卖第: 14张票
    Thread-1 正在卖第: 13张票
    Thread-1 正在卖第: 12张票
    Thread-1 正在卖第: 11张票
    Thread-1 正在卖第: 10张票
    Thread-1 正在卖第: 9张票
    Thread-1 正在卖第: 8张票
    Thread-1 正在卖第: 7张票
    Thread-1 正在卖第: 6张票
    Thread-1 正在卖第: 5张票
    Thread-1 正在卖第: 4张票
    Thread-1 正在卖第: 3张票
    Thread-1 正在卖第: 2张票
    Thread-1 正在卖第: 1张票
    

    ③Lock锁

    java.util.concurrent.locks.Lock机制提供比使用synchronized方法和语句可以获得的更广泛的锁定操作。同步代码块/同步方法所具有的的方法,Lock都有,除此之外还更强大,更体现面向对象

    • public interface Lock
      

      Lock实现提供比使用synchronized方法和语句可以获得的更广泛的锁定操作。它们允许更灵活的结构化,可能具有完全不同的属性,并且可以支持多个相关联的对象Condition

      锁是用于通过多个线程控制对共享资源的访问的工具。 通常,锁提供对共享资源的独占访问:一次只能有一个线程可以获取锁,并且对共享资源的所有访问都要求首先获取锁。 但是,一些锁可能允许并发访问共享资源,如ReadWriteLock的读锁。

      使用synchronized方法或语句提供对与每个对象相关联的隐式监视器锁的访问,但是强制所有锁获取和释放以块结构的方式发生:当获取多个锁时,它们必须以相反的顺序被释放,并且所有的锁都必须被释放在与它们相同的词汇范围内。

      虽然synchronized方法和语句的范围机制使得使用监视器锁更容易编程,并且有助于避免涉及锁的许多常见编程错误,但是有时您需要以更灵活的方式处理锁。 例如,用于遍历并发访问的数据结构的一些算法需要使用“手动”或“链锁定”:您获取节点A的锁定,然后获取节点B,然后释放A并获取C,然后释放B并获得D等。 所述的实施方式中Lock接口通过允许获得并在不同的范围释放的锁,并允许获得并以任何顺序释放多个锁使得能够使用这样的技术。

    • 同时加锁和解锁进行方法化

      void lock():获得锁

      void unlock():释放锁

    • 代码实现:

      /*
      * 使用Lock锁来解决卖票案例中产生的线程安全问题
      * Lock的实现类:java.util.concurrent.locks.ReentrantLock implements Lock
       * 使用步骤:1.在Runnable实现类的成员位置创建Lock的实现类
       *         2.在可能出现安全问题的代码处调用Lock的方法void lock();获取锁
       *         3.在可能出现安全问题的代码后调用Lock的方法void unlock();方法解锁
      *
       * */
      public class RunnableImpl implements Runnable{
          private int ticket = 100;
          //1.在Runnable实现类的成员位置创建Lock的实现类
          Lock lock = new ReentrantLock();
          @Override
          public void run() {
              while (true){
                  //2.在可能出现安全问题的代码处调用Lock的方法void lock();获取锁
                  lock.lock();
                  try {
                      Thread.sleep(10);
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
                  if (ticket>0) {
                      System.out.println(Thread.currentThread().getName()+" 正在卖第: "+ ticket +"张票");
                      ticket--;
                  }
                  //3.在可能出现安全问题的代码后调用Lock的方法void unlock();方法解锁
                  lock.unlock();
              }
          }
      }
      //主方法开启三个线程
      /*
      * 创建三个线程让这三个线程都对共享的票进行出售
      * 共享体现在只有一个runnable的实现类,但是用三个线程来执行
      * */
      public class DemoMain {
          public static void main(String[] args) {
              RunnableImpl run = new RunnableImpl();
              Thread t1 = new Thread(run);
              Thread t2 = new Thread(run);
              Thread t3 = new Thread(run);
              t1.start();
              t2.start();
              t3.start();
      
          }
      }
      

      打印结果:解决了线程安全问题

      Thread-0 正在卖第: 100张票
      Thread-0 正在卖第: 99张票
      Thread-0 正在卖第: 98张票
      Thread-0 正在卖第: 97张票
      Thread-0 正在卖第: 96张票
      Thread-0 正在卖第: 95张票
      Thread-0 正在卖第: 94张票
      Thread-0 正在卖第: 93张票
      Thread-0 正在卖第: 92张票
      Thread-0 正在卖第: 91张票
      Thread-0 正在卖第: 90张票
      Thread-0 正在卖第: 89张票
      Thread-0 正在卖第: 88张票
      Thread-0 正在卖第: 87张票
      Thread-0 正在卖第: 86张票
      Thread-0 正在卖第: 85张票
      Thread-0 正在卖第: 84张票
      Thread-0 正在卖第: 83张票
      Thread-0 正在卖第: 82张票
      Thread-0 正在卖第: 81张票
      Thread-0 正在卖第: 80张票
      Thread-0 正在卖第: 79张票
      Thread-0 正在卖第: 78张票
      Thread-0 正在卖第: 77张票
      Thread-0 正在卖第: 76张票
      Thread-1 正在卖第: 75张票
      Thread-1 正在卖第: 74张票
      Thread-1 正在卖第: 73张票
      Thread-1 正在卖第: 72张票
      Thread-1 正在卖第: 71张票
      Thread-1 正在卖第: 70张票
      Thread-1 正在卖第: 69张票
      Thread-1 正在卖第: 68张票
      Thread-1 正在卖第: 67张票
      Thread-1 正在卖第: 66张票
      Thread-1 正在卖第: 65张票
      Thread-1 正在卖第: 64张票
      Thread-1 正在卖第: 63张票
      Thread-1 正在卖第: 62张票
      Thread-1 正在卖第: 61张票
      Thread-1 正在卖第: 60张票
      Thread-1 正在卖第: 59张票
      Thread-1 正在卖第: 58张票
      Thread-1 正在卖第: 57张票
      Thread-1 正在卖第: 56张票
      Thread-1 正在卖第: 55张票
      Thread-1 正在卖第: 54张票
      Thread-1 正在卖第: 53张票
      Thread-1 正在卖第: 52张票
      Thread-1 正在卖第: 51张票
      Thread-1 正在卖第: 50张票
      Thread-1 正在卖第: 49张票
      Thread-1 正在卖第: 48张票
      Thread-1 正在卖第: 47张票
      Thread-1 正在卖第: 46张票
      Thread-1 正在卖第: 45张票
      Thread-1 正在卖第: 44张票
      Thread-1 正在卖第: 43张票
      Thread-1 正在卖第: 42张票
      Thread-1 正在卖第: 41张票
      Thread-1 正在卖第: 40张票
      Thread-1 正在卖第: 39张票
      Thread-1 正在卖第: 38张票
      Thread-1 正在卖第: 37张票
      Thread-1 正在卖第: 36张票
      Thread-1 正在卖第: 35张票
      Thread-1 正在卖第: 34张票
      Thread-1 正在卖第: 33张票
      Thread-1 正在卖第: 32张票
      Thread-1 正在卖第: 31张票
      Thread-1 正在卖第: 30张票
      Thread-1 正在卖第: 29张票
      Thread-1 正在卖第: 28张票
      Thread-1 正在卖第: 27张票
      Thread-1 正在卖第: 26张票
      Thread-1 正在卖第: 25张票
      Thread-1 正在卖第: 24张票
      Thread-1 正在卖第: 23张票
      Thread-1 正在卖第: 22张票
      Thread-1 正在卖第: 21张票
      Thread-1 正在卖第: 20张票
      Thread-1 正在卖第: 19张票
      Thread-1 正在卖第: 18张票
      Thread-1 正在卖第: 17张票
      Thread-1 正在卖第: 16张票
      Thread-1 正在卖第: 15张票
      Thread-1 正在卖第: 14张票
      Thread-1 正在卖第: 13张票
      Thread-1 正在卖第: 12张票
      Thread-1 正在卖第: 11张票
      Thread-1 正在卖第: 10张票
      Thread-1 正在卖第: 9张票
      Thread-1 正在卖第: 8张票
      Thread-1 正在卖第: 7张票
      Thread-1 正在卖第: 6张票
      Thread-1 正在卖第: 5张票
      Thread-1 正在卖第: 4张票
      Thread-1 正在卖第: 3张票
      Thread-1 正在卖第: 2张票
      Thread-1 正在卖第: 1张票
      
      
         可以看API文档优化以下lock锁部分,把unlock放到finally
      
public class RunnableImpl implements Runnable{
    private int ticket = 100;
    //1.在Runnable实现类的成员位置创建Lock的实现类
    Lock lock = new ReentrantLock();
    @Override
    public void run() {
        while (true){
            //2.在可能出现安全问题的代码处调用Lock的方法void lock();获取锁
            lock.lock();
            try {
                Thread.sleep(10);
                if (ticket>0) {
                    System.out.println(Thread.currentThread().getName()+" 正在卖第: "+ ticket +"张票");
                    ticket--;
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                //3.在可能出现安全问题的代码后调用Lock的方法void unlock();方法解锁
                lock.unlock();//无论程序是否异常都会把锁给释放掉,提高程序效率
            }


        }
    }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值