此篇博客已售票例子为例,所以首先看一个synchronized(同步锁机制)的案例

 

synchronized(同步锁机制)的案例

package android.java.thread19;

/**
 * 售票线程
 */
class Booking implements Runnable {

    /**
     * 模拟票的总算 10张票
     */
    private int ticket = 10;

    @Override
    public void run() {

        while (true) {

            /**
             * 加入了同步代码块的代码synchronized,
             * 不管CPU如何疯狂的切换执行,
             * 只要同步代码块里面的代码没有执行完,
             * 就不准其他线程进来执行
             * 这样就保证了多线程操作共享数据的安全新
             */
            synchronized (Booking.class) { // 同步操作共享数据的代码

                if (ticket > 0) {

                    // 让线程在这里停一下,会更加容易复现线程的安全问题,就算不加这行代码,安全问题依然有
                    try {
                        Thread.sleep(200);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    System.out.println("名称:" + Thread.currentThread().getName() + "窗口卖出第" + ticket + "张票");
                    ticket--;
                }
            }

        }

    }
}

/**
 * 售票案例
 */
public class LockTestDemo {

    public static void main(String[] args) {

        /**
         * 定义Runnable实现类Booking,此实现类Booking不是线程,此实现类Booking给四个Thread去执行的
         */
        Runnable booking = new Booking();

        // 实例化线程对象
        Thread thread1 = new Thread(booking); // 此实现类Booking给Thread去执行的
        Thread thread2 = new Thread(booking); // 此实现类Booking给Thread去执行的
        Thread thread3 = new Thread(booking); // 此实现类Booking给Thread去执行的
        Thread thread4 = new Thread(booking); // 此实现类Booking给Thread去执行的

        // 开启启动线程
        thread1.start(); // 启动第Thread-0窗口 执行卖票任务
        thread2.start(); // 启动第Thread-1窗口 执行卖票任务
        thread3.start(); // 启动第Thread-2窗口 执行卖票任务
        thread4.start(); // 启动第Thread-3窗口 执行卖票任务


    }

}

执行结果:

 

 


 

 

 

在JDK1.5以前是使用synchronized(同步锁机制),以上 (synchronized(同步锁机制)的案例)就是使用synchronized同步锁机制

synchronized同步锁机制,是隐式的,什么时候锁住,什么时候释放锁,锁是什么锁🔒...... ,这个是看不到的,例如:

 public synchronized(锁🔒是当前this) void exit() {
        // ....
  }
 public static synchronized(锁🔒是 当前类名.class) void actionTicket() { 
        // .....
  }  
  synchronized (厕所门显示无人 🔓) {
      // 上厕所任务
      ........
   }

   synchronized (厕所门显示有人 🔒) {
      // 上厕所任务
      ........
   }

 

而以下案例使用 Lock 接口来完成,同步锁机制,可以理解为:Lock是synchronized的升级版

Lock这种同步锁机制,是灵活的,是看得见的,什么时候锁住,什么时候释放锁,锁是什么锁🔒...... ,这个是看到的,例如:

    // 定义一个锁🔒      
       private Lock lock = new ReentrantLock();      

       // 🔒锁定 锁住
       lock.lock();

       // 多线程/多地方调用 执行操作共享数据的代码 .......

       // 🔓释放锁

 

把synchronized 修改成>>> Lock接口 的案例:

使用规则:必须使用 try {}finally{}  意思是:万一发生异常 或者 发生什么 ....... 导致没有释放锁🔒,从而引发严重错误❌, 加入以下代码控制的意思是:不管发生什么一定会释放锁🔒

     try {

        }finally {
            // 释放锁🔒
        }

案例

package android.java.thread19;

import android.util.Log;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 售票线程
 */
class Booking implements Runnable {

    /**
     * 模拟票的总算 10张票 - 共享数据
     */
    private int ticket = 10;

    /**
     * Lock是接口不是直接实例化,需要实例化Lock的实现类ReentrantLock,这样就创建了一把锁🔒
     */
    private Lock lock = new ReentrantLock();

    @Override
    public void run() {

        while (ticket > 0) {

            /**
             * 锁🔒定 操作共享数据的代码
             * 只要锁定后 不管CPU如何疯狂的切换执行,只要同步代码块里面的代码没有执行完,
             * 就不准其他线程进来执行,这样就保证了多线程操作共享数据的安全新
             */
            lock.lock();

            try {

                // 加这个判断是为了处理线程安全🔐问题,例如:多个线程刚刚进入while后 马上被临时阻塞了,从而引发安全问题
                if (ticket > 0) {

                    // 让线程在这里停一下,会更加容易复现线程的安全问题,就算不加这行代码,安全问题依然有
                    try {
                        Thread.sleep(200);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    System.out.println("名称:" + Thread.currentThread().getName() + "窗口卖出第" + ticket + "张票");
                    ticket--;
                }

            } finally {
                /**
                 * 释放锁🔓,锁是资源
                 * 释放锁🔒后 就不再持有锁🔒
                 * 当不再持有锁🔒,其他然后线程都可以执行进入代码了
                 *
                 * 注意⚠:一旦锁定后,就一旦要释放锁,否则所以线程都进不了锁定的代码
                 */
                lock.unlock();
                // System.out.println("释放锁🔒");
            }
        }

    }
}

/**
 * 售票案例
 */
public class LockTestDemo {

    public static void main(String[] args) {

        /**
         * 定义Runnable实现类Booking,此实现类Booking不是线程,此实现类Booking给四个Thread去执行的
         */
        Runnable booking = new Booking();

        // 实例化线程对象
        Thread thread1 = new Thread(booking); // 此实现类Booking给Thread去执行的
        Thread thread2 = new Thread(booking); // 此实现类Booking给Thread去执行的
        Thread thread3 = new Thread(booking); // 此实现类Booking给Thread去执行的
        Thread thread4 = new Thread(booking); // 此实现类Booking给Thread去执行的

        // 开启启动线程
        thread1.start(); // 启动第Thread-0窗口 执行卖票任务
        thread2.start(); // 启动第Thread-1窗口 执行卖票任务
        thread3.start(); // 启动第Thread-2窗口 执行卖票任务
        thread4.start(); // 启动第Thread-3窗口 执行卖票任务


    }

}

 

执行结果: