线程安全问题产生的原因
1、多个线程在操作共享的数据
2、操作共享数据的线程代码有多条
当一个线程在执行共享数据的多条代码过程中,其他线程参与了运算,就会导致线程安全问题的产生
如何解决呢?需要使用同步代码块解决
synchronize(obj){
//代码…
}
同步的好处:可以解决线程安全问题
同步的缺点:降低处理效率,因为同步外的线程会判断同步锁
同步的前提:同步中必须有多个线程并使用同一个锁
同步函数和同步代码块的区别:
同步代码块的锁是任意一个对象
同步函数的锁是该函数所属的字节码文件对象,也可以写成this.getClass。
例1:
两个客户去银行存款,银行有自己的资金总额,客户每次存100,共存三次,计算资金总额是多少。
public class BankDemo {
private int money = 0;//银行资金总额
public void add(int num){ //资金增加方法
money = money + num;
System.out.println(Thread.currentThread().getName()+"..."+money);
}
public static void main(String[] args) { //客户类
Cus c = new Cus();
Thread t1 = new Thread(c); //创建两个线程
Thread t2 = new Thread(c);
t1.start(); //开启线程
t2.start();
}
public static class Cus implements Runnable{
BankDemo b = new BankDemo();
public synchronized void run(){ //同步方法 锁是this,指的cus对象
for(int i = 0;i<3;i++){ //存三次
b.add(100); //每次存100
}
}
}
}
运行结果
Thread-0...100
Thread-0...200
Thread-0...300
Thread-1...400
Thread-1...500
Thread-1...600
例2
使用单例模式实现线程安全
1、饿汉式
由于在创建对象时就进行了初始化,当多个线程运行getInstance方法时,不会再去new对象,所以是线程安全的
伪代码:
private static Single s = new Single();
private Single(){}
public static Single getInstance(){
return s;
}
2、懒汉式
private static Single s = null; //声明1个单例对象
private void Single(){} //构造方法
public static Single getInstance(){ //获取实例方法
if(s == null){ //增加效率
synchronized(Single.class){ //解决线程安全问题
if(s == null){
s = new Single();
}
}
}
return s;
}