出现的问题:
① 相同的票卖了多次 ==> CPU的一次操作必须是原子性的
② 出现了负数票 ==> 线程的随机性及延迟导致
这就是多线程操作导致的共享数据操作出现问题,即线程不安全。 导致线程不安全的原因:
① 多线程环境
② 存在共享数据
③ 存在多条语句操作共享数据(读、写) 2、线程同步 1. 同步代码块
同步的关键是管程(也叫信号量semaphore)的概念。管程是一个互斥独占锁定的对象,或称互斥体(mutex)。在给定的时间,仅有一个线程可以获得管程。当一个线程需要锁定,它必须进入管程。所有其他的试图进入已经锁定的管程的线程必须挂起直到第一个线程退出管程。这些其他的线程被称为等待管程。一个拥有管程的线程如果愿意的话可以再次进入相同的管程。 格式:
synchronized(对象){
需要同步的代码;
} 注意:
① 同步体的内容相当于一个原子操作;
② 多个线程必须是同一把锁;
③ 锁对象可以是任意对象。
避免死锁的方式:
① 让程序每次至多只能获得一个锁。当然,在多线程环境下,这种情况通常并不现实
② 设计时考虑清楚锁的顺序,尽量减少嵌在的加锁交互数量
③ 既然死锁的产生是两个线程无限等待对方持有的锁,那么只要等待时间有个上限不就好了。当然synchronized不具备这个功能,但是我们可以使用Lock类中的tryLock方法去尝试获取锁,这个方法可以指定一个超时时限,在等待超过该时限之后变回返回一个失败信息。 5、线程间通信---> 生产者和消费者模式
Object类中提供了几个方法:
public final void wait() --------------> 线程进入等待阻塞状态,让出CPU执行权。
public final void notify() ------------> 唤醒在此对象监视器上等待的单个线程。如果所有线程都在此对象上等待,则会选择唤醒其中任意一个线程。
public final void notifyAll() ---------> 唤醒在此对象监视器上等待的所有线程。
生产者和消费者模型是线程模型中的经典模型:生产者和消费者在同一时间段内共用同一存储空间,生产者向空间里生产数据,而消费者取走数据。
--> 资源类:Student
--> 设置学生数据:SetThread(生产者)
--> 获取学生数据:GetThread(消费者)
--> 测试类:StudentDemo