解决线程安全问题_使用Lock锁

卖票案例出现了线程安全问题
卖出了不存在的票和重复的票

解决线程安全问题的第三种方案:使用Lock锁

java.util.concurrent.locks.Lock接口
Lock实现提供更广泛的锁定操作可以比使用 synchronized获得方法和报表

Lock接口中的方法
void lock() 获取锁
void unlock() 释放锁
java.util.concurrent.locks.ReentrantLock implements Lock接口

使用步骤:
1.在成员位置创建一个ReentrantLock对象
2.在可能会出现安全问题代码前调用Lock接口中的方法Lock获取锁
3.在可能会出现安全问题的后调用Lock接口中的方法unlock释放锁

package com.Thread.Lock;

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

/*
     卖票案例出现了线程安全问题
     卖出了不存在的票和重复的票

     解决线程安全问题的第三种方案:使用Lock锁
     java.util.concurrent.locks.Lock接口
     Lock实现提供更广泛的锁定操作可以比使用 synchronized获得方法和报表
     Lock接口中的方法:
            void lock()   获取锁
            void unlock() 释放锁
     java.util.concurrent.locks.ReentrantLock implements Lock接口

     使用步骤:
         1.在成员位置创建一个ReentrantLock对象
         2.在可能会出现安全问题代码前调用Lock接口中的方法Lock获取锁
         3.在可能会出现安全问题的后调用Lock接口中的方法unlock释放锁
 */
public class RunnableImpl implements Runnable {
    //定义一个多个线程共享的资源
    private  int ticket = 100;

 // 1.在成员位置创建一个ReentrantLock对象
    Lock l = new ReentrantLock();

    //设置线程任务:卖票
    @Override
    public void run() {
        //使用死循环,让卖票操作重复进行
        while (true){
        //2.在可能会出现安全问题代码前调用Lock接口中的方法Lock获取锁
            l.lock();
                //先判断票是否存在
                if (ticket>0){
                    //提高安全问题出现的概率,让程序睡眠
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    //票存在,卖票 ticket--
                    System.out.println(Thread.currentThread().getName()+"-->正在卖第"+ticket+"张票");
                    ticket--;
                }
            //3.在可能会出现安全问题的后调用Lock接口中的方法unlock释放锁
             l.unlock();
        }
    }
}

测试类

package com.Thread.Lock;

/*
   模拟卖票案例
   创建3个线程,同时开启,对共享的票进行出售
 */
public class Demo01Ticket {
    public static void main(String[] args) {
        //创建Runnable接口的实现类对象
        RunnableImpl run = new RunnableImpl();
        //创建Thread类对象。构造方法中传递Runnable接口的实现对象
        Thread t0 = new Thread(run);
        Thread t1 = new Thread(run);
        Thread t2 = new Thread(run);
        //调用start方法开启多线程
        t0.start();
        t1.start();
        t2.start();
    }
}

Lock锁优化版

package com.Thread.Lock;

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

public class RunnableImpl02 implements Runnable {
    //定义一个多个线程共享的资源
    private  int ticket = 100;

 // 1.在成员位置创建一个ReentrantLock对象
    Lock l = new ReentrantLock();

    //设置线程任务:卖票
    @Override
    public void run() {
        //使用死循环,让卖票操作重复进行
        while (true){
        //2.在可能会出现安全问题代码前调用Lock接口中的方法Lock获取锁
            l.lock();
                //先判断票是否存在
                if (ticket>0){
                    //提高安全问题出现的概率,让程序睡眠
                    try {
                        Thread.sleep(10);
                        //票存在,卖票 ticket--
                        System.out.println(Thread.currentThread().getName()+"-->正在卖第"+ticket+"张票");
                        ticket--;
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }finally {
                        //3.在可能会出现安全问题的后调用Lock接口中的方法unlock释放锁
                        l.unlock();  //无论程序是否异常,都会把锁释放掉
                    }
                }
        }
    }
}

你可能感兴趣的:(java,多线程)