线程安全问题
1.synchronized 关键字。
其实是一个内置锁,通过锁对象的moinitor的取用与释放,
来实现加锁和解锁。锁对象可以是任何一个对象。
synchronized 关键字实现同步代码块
sychronized(同步监视器){
//需要同步的代码
}
同步监视器==锁对象,
Object obj = new Object();
需要同步的代码 = 操作共享数据的代码
共享数据:多个线程共同操作的变量。
要求:多个线程必须要共用同一把锁。
缺点: 同步代码块里面只有一个线程,其他线程在等待,效率低。
继承Thread类的方式的线程安全问题。
- 把锁变量变成静态的
private static Object obj = new Obejct();
整个static,锁对象唯一
因为继承thread类的线程类
每一个线程对象都有一个实例变量。
如果实现Runnable接口的实现类中,
实例变量都是共享的
因为这些实现类的对象是作为Thread类对象的target对象。
刚刚是new了一个锁变量,
为了方便,我们可以用当前对象充当。this
继承Thread类的不行,
拿当前的类去充当同步监视器。
2.synchronized 关键字实现同步方法
继承Thread类
private static synchronized void show(){
public void run (){
同步监视器:默认当前类
而且同步方法要弄成静态的
因为可能存在多个线程。
3.Lock锁,显示定义同步锁
lock==接口
要用接口的具体实现类, ReentrantLock
使用这个ReentrantLock的对象,解决线程安全问题。
在Runnable接口的实现类中。
1.造一个ReentrantLock对象,
private ReentantLock lock = new ReentrantLock();
ReentrantLock 有构造器,
参数是fair,如果为true,就是创建一个公平的Lock
公平锁的意思就是,
多个线程访问这个同步资源,有先后顺序。
同步资源让先来的线程执行。
把需要同步的代码,放进try里面,
try里面,ReentrantLock对象调用lock方法,
====线程获取了同步监视器。
try{ lock.lock(); 执行需要同步代码 }
所以保证在同步代码中,他是单线程。
代码出现异常,执行finally代码。
finally里面,ReentrantLock对象调用unlock方法(解锁)。
finally{ lock.unlock(); }
synchronized与lock的区别,
都解决线程了安全问题
synchronized机制在执行完同步代码以后,自动释放了同步监视器。
lock需要手动实现同步,调用lock方法。
手动的结束同步。调用unlock方法。
死锁
死锁就是,不同的线程分别占用对方所需要的同步资源,不放弃,
等待对方放弃自己所需要的同步资源。
1.死锁形成的四个条件
1.互斥使用,资源的固有属性
2.不可抢占,
3.请求和保持
4.环路等待
死锁预防,
1.在进程执行前,一次性申请所有需要的资源。
对资源类型进行排序,资源申请必须按序申请,资源浪费。
预知很难,资源利用率低。
判断此次,资源请求是否会引起死锁。
用银行家算法。
系统中所有进程存在一个可完成的执行序列。
P1,。。。。Pn
系统就处于安全状态。
申请一个work变量,每次判断进程所需的各种资源是不是小于work。
(剩下的资源,需要的资源)
定期检测,cpu利用率低的时候,是不是死锁了。