线程安全问题

产生原因:多个线程竞争同一资源(访问同一数据),可参考经典的生产者消费者问题。

解决方案:run 方法内:同步代码块 synchronized {}

Public synchronized 返回值类型 方法名(){} 自动释放对象锁

使用 Lock 锁 Lock 锁需要程序员(在 finally 代码块中)手动释放。

Lock lock=new ReentranttLock()    // Reentrant(可重用的)

Lock 实现提供了比使用 synchronized 方法和语句可获得的更广泛的锁定操作,是 JDK1.5 之后出现的。

Lock 接口中的方法:

void lock()   // 获取锁 
void unlock() // 释放锁 

Lock 接口的实现类:

java.util.concurrent.locks.ReentrantLock implements Lock
/*
使用步骤:
- 1.在成员位置创建一个 ReentrantLock 对象。
- 2.在可能出现线程安全问题的代码前,调用 Lock 接口中的方法 lock 获取锁对象。
- 3.在可能出现线程安全问题的代码后,调用 Lock 接口中的方法 unlock 释放锁对象。
*/
public class RunnableImpl implements Runnable{
    private int ticket = 100;//定义一个共享的票源
    Lock l = new ReentrantLock();//1.在成员位置创建一个ReentrantLock对象
    //设置线程任务:卖票
    public void run() {
        while(true){//重复的执行卖票动作
            l.lock();//2.在可能出现线程安全问题的代码前,调用Lock接口中的方法lock获取锁对象
            if(ticket>0){//判断票数是否大于0
                //为了提高线程安全问题出现的几率,让程序睡眠10毫秒
                try {
                    //可能会产生异常的代码
                    Thread.sleep(10);
                    //进行卖票 ticket--
                    System.out.println(Thread.currentThread().getName()+"正在卖第"+ticket+"张票!");
                    ticket--;
                } catch (InterruptedException e) {
                    e.printStackTrace();//异常处理
                }finally {
                    //一定会执行的代码,一般用于资源释放(资源回收)
                    //3.在可能出现线程安全问题的代码后,调用Lock接口中的方法unlock释放锁对象
                    l.unlock();//无论程序是否有异常,都让锁对象释放掉,节约内存,提高程序的效率
                }
            }
        }
    }
}

你可能感兴趣的:(笔记)