二,线程安全
一,三类线程安全问题
当多个线程同时访问一个对象,如果不用考虑线程之间的协作,不需要额外的同步控制,就可以得到正确的结果,那么这个对象是线程安全的。
常见的线程安全错误有三种:
1,运行结果错误
public static void main(String[] args) throws Exception {
Runnable r = ()->{
for(int i = 0; i < 1000; i++){
a++;
}
};
Thread t1 = new Thread(r);
Thread t2 = new Thread(r);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(a);
}
由于a++非原子操作,导致a最终的结果不是2000
2,发布和初始化导致线程安全问题
如果在线程中发布或初始化变量,由于无法保证线程开始运行的时间,导致数据没有按照顺序执行。
3,活跃性问题
分为死锁、活锁、饥饿
死锁,当两个线程相互拥有对方等待的资源,同时又等待对方的资源。这样就造成死锁。
Object o1 = new Object(),o2 = new Object();
public void thread1(){
synchronized (o1) {
try {
Thread.sleep(1000);
synchronized(o2){
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void thread2(){
synchronized (o2) {
try {
Thread.sleep(1000);
synchronized(o1){
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws Exception {
P3 p = new P3();
new Thread(()->{p.thread1();}).start();
new Thread(()->{p.thread2();}).start();
}
活锁,指发送在循环中的错误,一直执行,但是一直失败
饥饿,线程需要的资源始终无法得到,而导致线程一直无法运行。
二,需要注意线程安全的场景
1,访问共享变量和资源
比如多个线程同时访问static变量
2,依赖时序的操作
比如检查-执行操作。
if(x == 7)
x = 2 * x;
先检查,后执行,这两步操作不是原子的,如果多个线程同时运行,就需要加锁保证原子性。
3,不同数据之间存在绑定关系
4,对方没有声明自己是线程安全的
三,为什么多线程会带来性能问题
1,线程调度的开销
上下文切换,缓存失效
2,线程协作的开销

浙公网安备 33010602011771号