Java学习19天
线程安全的同步
线程生命周期(需要掌握)
1.问题:卖票过程中,出现了重票、错票(0,-1。。。)–>出现了线程的安全问题
2.问题出现的原因:当某个线程操作车票的过程中,尚未操作完成时,其他线程参与进来,也操作车票(共享数据)
3.如何解决:当一个线程a在操作ticket的时候,其他线程不能参与进来。直到线程a操作完ticket时其他线程才可以开始操作ticket。这种情况即使线程a出现了阻塞,也不能被改变。
在Java中,我们通过同步机制,来解决线程的安全问题。
方式一:同步代码块
说明:
- 在实现Runnable接口创建多线程的方式中,我们可以考虑使用this充当同步监视器。(具体问题具体分析)
- 在继承Thread类创建多线程的方式中,慎用this充当同步监视器,考虑使用当前类充当同步监视器(当前类.class)(具体问题具体分析)
方式二:同步方法
如果操作共享数据的代码完整的声明在一个方法中,我们不妨将此方法声明同步的。
例:private synchronized void method(){
。。。
}
关于同步方法的总结:
1.同步方法仍然涉及到同步监视器,只是不需要我们显式的声明。
2.非静态的同步方法,同步监视器是: this(例如实现runnable接口的)
静态的同步方法,同步监视器是:当前类本身:当前类.class(例如继承Thread类的)
同步的方式,解决了线程的安全问题。—好处
操作同步代码时,只能有一个线程参与,其他线程等待。相当于是一个单线程的过程,效率低。—局限性
使用同步机制将单例模式中的懒汉式改写为线程安全的
解决线程安全问题的方式三: Lock锁— JDK5.0新增
例:
注意:在实现类中使用Lock锁时要加static,保证是同一把锁
面试题: sleep()和wait()的异同?
1.相同点:一旦执行方法,都可以使得当前的线程进入阻塞状态。
2.不同点:1)两个方法声明的位置不同:Thread类中声明sleep() , object类中声明wait()
2)调用的要求不同: sleep()可以在任何需要的场景下调用。wait()必须使用在同步代码块或同步方法
3)关于是否释放同步监视器:如果两个方法都使用在同步代码块或同步方法中,sleep()不会释放锁,wait()会释放锁