Java学习19天

线程安全的同步

线程生命周期(需要掌握)
Java学习19天
1.问题:卖票过程中,出现了重票、错票(0,-1。。。)–>出现了线程的安全问题
2.问题出现的原因:当某个线程操作车票的过程中,尚未操作完成时,其他线程参与进来,也操作车票(共享数据)
3.如何解决:当一个线程a在操作ticket的时候,其他线程不能参与进来。直到线程a操作完ticket时其他线程才可以开始操作ticket。这种情况即使线程a出现了阻塞,也不能被改变。


在Java中,我们通过同步机制,来解决线程的安全问题。

方式一:同步代码块

Java学习19天
说明:

  1. 在实现Runnable接口创建多线程的方式中,我们可以考虑使用this充当同步监视器。(具体问题具体分析)
  2. 在继承Thread类创建多线程的方式中,慎用this充当同步监视器,考虑使用当前类充当同步监视器(当前类.class)(具体问题具体分析)

方式二:同步方法

如果操作共享数据的代码完整的声明在一个方法中,我们不妨将此方法声明同步的。
例:private synchronized void method(){
。。。
}
关于同步方法的总结:
1.同步方法仍然涉及到同步监视器,只是不需要我们显式的声明。
2.非静态的同步方法,同步监视器是: this(例如实现runnable接口的)
静态的同步方法,同步监视器是:当前类本身:当前类.class(例如继承Thread类的)


同步的方式,解决了线程的安全问题。—好处
操作同步代码时,只能有一个线程参与,其他线程等待。相当于是一个单线程的过程,效率低。—局限性


使用同步机制将单例模式中的懒汉式改写为线程安全的
Java学习19天
Java学习19天


Java学习19天

解决线程安全问题的方式三: Lock锁— JDK5.0新增

例:
Java学习19天

Java学习19天
注意:在实现类中使用Lock锁时要加static,保证是同一把锁
Java学习19天

Java学习19天


Java学习19天
面试题: sleep()和wait()的异同?
1.相同点:一旦执行方法,都可以使得当前的线程进入阻塞状态。
2.不同点:1)两个方法声明的位置不同:Thread类中声明sleep() , object类中声明wait()
2)调用的要求不同: sleep()可以在任何需要的场景下调用。wait()必须使用在同步代码块或同步方法
3)关于是否释放同步监视器:如果两个方法都使用在同步代码块或同步方法中,sleep()不会释放锁,wait()会释放锁

线程创建方法:

一、继承Thread类

二、实现Runnable接口

三、实现Callable接口

Java学习19天
Java学习19天
Java学习19天
Java学习19天
Java学习19天

四、使用线程池(开发常用)

Java学习19天
Java学习19天