Java多线程 线程安全一本通,线程安全,为什么要用多线程,如何同步,单例模式线程安全

  • 为什么要同步?
线程彼此 相互独立,对于同一数据,多线程都可以读取,就会产生异常和矛盾;
比如LOL:Hero类,一个对象为盖伦Gareen,血量1000,一个线程加血addHp(),一个线程减血reduceHp()
正常情况下:
血量为1000
addHp() +1=1001
reduceHp() -1=1000
实际上由于线程独立性:两个线程读到的都是1000(在另一个线程写入之前读入)
血量为1000
addHp() reduceHp()
+1=1001写入 -1=999写入
所以结果 可能是1001,也可能是999,产生脏数据
所以我们要使用同步保证共享资源的互斥操作;
  • 同步
同步代码块:
Object someObject =new Object();
synchronized (someObject){
//此处的代码只有占有了someObject后才可以执行
}
synchronized表示当前线程独占对象 someObject。当前线程独占了对象someObject,如果有其他线程试图占有对象someObject,就会等待,直到当前线程释放对someObject的占用。
someObject 又叫同步对象,所有的对象,都可以作为同步对象为了达到同步的效果,必须使用同一个同步对象。既然现在都是调用Hero类实例的方法,不如直接使用Hero类实例,可以在main函数中声明
synchronized(Gareen){
Gareen.addHp();
}
也可以在类中定义,如果使用同步代码块,填入this指针指定当前类对象为同步对象,使用函数同步声明,和同步块指定当前对象是一样的,如下所示;
public Class Hero{
private float hp=1000;
public synchronized void addHp(){
hp=hp+1;
}
public void reduceHp(){
synchronized (this) {
hp=hp-1;
}
}
}

  • 静态方法同步
Hero类中的普通方法,通过对象调用,如Gareen.addHp()
而静态方法通过类名直接调用,如下面修改后的Hero.addHp(),因为 任何类是Class类的实例,而对应的实例就是Hero类的类类型(详见反射)
http://blog.csdn.net/evanxuhe/article/details/75420186
Hero.class,因而这次静态代码块声明用的是当前类的类类型Hero.class
public Class Hero{
private float hp=1000;
public static synchronized void addHp(){
hp=hp+1;
}
public void reduceHp(){
synchronized (Hero.class) {
hp=hp-1;
}
}
}
  • 线程安全的应用案例
String,StringBuider,StringBuffer
StringBuffer是线程安全的,所有方法都有sychrosized声明,代价就是慢,因为线程要等嘛,越安全越慢
而像String,StringBuilder都有危险,比如两个线程访问一个String,一个增加字符,一个删除字符,可能的结果是只增不减,或者只减不增。
HashMap和HashTable
类似,HashTable线程安全,不会有矛盾。
单例模式:饿汉模式与懒汉模式
饿汉模式线程安全,但是懒汉模式非线程安全,可能会创建多个对象;

懒汉模式两种同步声明:因为涵盖了整个代码部分,所以效率低,比如加载要一个一个加载没必要



只同步一部分代码块,虽然高效,但是不同步,线程不安全;
因为在预加载的时间过程中(300ms),instance实例还未创建,所以一些进程会跳过外层判断进入,这些进程会OneByOne生成对象。

最优办法:
Double Check Locking 双检查锁机制 (推荐)
既能达到线程安全,又能提高代码执行效率,我们这里可以采用DCL的双检查锁机制来完成,代码实现如下:这样即使线程进入了外层循环,但是产生实例的时候会再判断,只有第一个进入的线程会创建实例。

  • 结语
多线程会产生很多异常和Bug(计算中的,数据库的...),但是又很难在测试中发现,因而学好多线程是开发应用的基本功。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值