1. 线程安全
说明时候会出现线程安全问题?
多线程执行有多条语句操作的共享数据
时
具体步骤:
- 明确哪些代码是多线程运行代码
- 明确共享数据
- 明确多线程运行代码中哪些语句是操作共享数据的
出现问题怎么解决?
同步代码块
synchronized(锁对象){
需要被同步的代码
}
对象如同锁,持有锁的线程才可以执行同步代码
没有锁的线程即使有cpu执行权,也进不去,因为没有锁
弊端:多个线程需要判断锁,较为消耗资源
同步函数
class Demo{
public synchronized void add(){
需要被同步的代码
}
}
同步函数的锁就是函数所属的对象引用 Demo.this
class Demo{
public static synchronized void add(){
需要被同步的代码
}
}
同步静态函数的锁不再是 Demo.this
静态进内存时,内存中没有本类对象,但是一定有该类的字节码文件对象
所以静态同步函数的锁是 Demo.class
2. 单例中的线程安全问题
// 饿汉式
class Single{
// final保证对象的唯一性
private static final Single s = new Single();
private Single(){}
public static Single getInstance(){
return s;
}
}
// 懒汉式(延时加载)
class Single{
private static Single s = null;
private Single(){}
public static Single getInstance(){
if(s == null){ // 操作了共享数据
s = new Single(); // 操作了共享数据
}
return s;
}
}
1. getInstance()方法中的代码是多线程运行的代码
2. 共享数据是 s(Single对象)
3. 有2条语句操作了共享数据
4. 所以多线程时会出现线程安全问题
---------------------------
class Single{
private static Single s = null;
private Single(){}
public static synchronized Single getInstance(){
if(s == null){ // 操作了共享数据
s = new Single(); // 操作了共享数据
}
return s;
}
}
通过修改成同步函数的方式来解决多线层下的安全问题
但是 return s; 语句并不需要同步,所以会降低程序运行效率
---------------------------
class Single{
private static Single s = null;
private Single(){}
public static Single getInstance(){
if(s == null){
synchronized(Single.class){
if(s == null){ // 操作了共享数据
s = new Single(); // 操作了共享数据
}
}
}
return s;
}
}
通过同步代码块的形式包裹需要同步的2行代码
再双重判断的形式提高程序运行的效率
3. 死锁是怎么产生的?
同步中嵌套同步
4. 等待唤醒机制
class Demo implements Runnable{
private Object o = new Object();
public void add(){
sychronized(o){
o.wait(); // 让“持有r锁的线程”变成等待状态
o.notify(); // 唤醒“持有r锁并处于等待状态”的线程
}
notifyAll(); // 唤醒所有”等待线程“
}
}
wait(), notify(), notifyAll() 都是Object对象的方法
5. JDK1.5 - Lock锁机制
Lock锁机制简介
将同步synchronized替换成了显式的Lock机制
将Object中的lock(), notify(), notifyAll() 替换成Condition对象
Condition对象可以通过lock.newCondition(); 获取
优点:可以指定不同锁对象上的线程 等待或者唤醒
Condition condition_a = lock.newCondition();
Condition condition_b = lock.newCondition();
condition_a.await(); // 让condition_a上的线程等待
condition_b.signal(); // 唤醒condition_b上的线程
常用方法
- await(): 让线程处于等待状态
- signal(): 唤醒一个等待线程
- signalAll(): 唤醒所有等待线程
// 相当于 synchronized
// 创建 Lock 接口的实例
private Lock lock = new ReentranLock();
// 相当于Object(wait, notify, notifyAll)
// 返回绑定到此 Lock 实例的新 Condition 实例
private Condition condition_pro = lock.newCondition();
private Condition condition_com = lock.newCondition();
// 获取锁
lock.lock();
// 让 ”condition对象“ 上的线程变成等待状态
condition_pro.await();
condition_com.await();
// 释放锁
// 该语句必须执行,所以放在finally中处理
lock.unlock();
// 从线程池中唤醒 “condition对象” 上的一个线程
condition_pro.signal();
condition_com.signal();
// 从线程池中唤醒 “condition对象” 上的所有线程
condition_pro.signalAll();
网友评论