线程安全要符合两点:原子性&可见性(加入个人理解:一致性,主内存和和线程内存的一致性)
结合这两点展开对volatile和synchronize的理解
-
使用退出标志,使线程正常退出,也就是当run方法完成后线程终止。 复制代码 -
使用stop方法强行终止线程(这个方法不推荐使用,因为stop和suspend、resume一样,也可能发生不可预料的结果)因为stop会释放锁,数据一致性得不到保障。 复制代码 -
使用interrupt方法中断线程。 复制代码
(1)线程处于阻塞状态,如使用了sleep方法。
(2)使用while(!isInterrupted()){…throw new InterruptedException…} (推荐方法:因为异常可以向上抛出,事件可以传播)
(3)interrupt与return结合(不能像使用throw new InterruptedException那样传播事件)
suspend、resume为什么废弃?
- 使用不当,造成同步方法独占,其他线程无法访问,造成死锁。
- 容易出现线程的暂停导致数据不同步。
Thread.suspend 天生容易引起死锁。如果目标线程挂起时在保护系统关键资源的监视器上持有锁,那么其他线程在目标线程恢复之前都无法访问这个资源。如果要恢复目标线程的线程在调用 resume 之前试图锁定这个监视器,死锁就发生了。这种死锁一般自身表现为“冻结( frozen )”进程。
GC是一个守护线程
关于变量是否线程安全的问题:
int num = 0在add方法外,如果多个run方法调用add方法时:非安全。
如果num = 0 在方法里面,则安全。
如果对这个num进行set get value,都要加synchronize,只对set加不对get加synchronize,那么另外的线程在get时会出现“脏读”。
可以参考《java并发编程》65页。
上面这一块儿也挺重要的,仔细阅读。
synchronize锁重入:自己可以再次获取自己的内部锁。
synchronize代码块带你的同步性问题,79也了解一下,第一遍不太懂。
package com.sankuai.qcs.risk.web.service;
/**
- Description:
- @author: zhangleilei
- @date: 2018/2/5
*/
public class Test {
public static void main(String[] args) {
Add[] adder = new Add[10];
for (int i = 0; i < 10; i++) {
adder[i] = new Add();
adder[i].start();
}
}
}
class Add extends Thread {
volatile public static int count = 0;
synchronized public void add() {
for (int i = 0; i < 10; i++) {
count++;
}
System.out.println("Thread:" + Thread.currentThread().getName() + ",Count:" + count);
}
@Override
public void run() {
super.run();
add();
}
复制代码
}
Thread:Thread-0,Count:10
Thread:Thread-1,Count:20
Thread:Thread-2,Count:30
Thread:Thread-3,Count:40
Thread:Thread-4,Count:50
Thread:Thread-5,Count:60
Thread:Thread-6,Count:70
Thread:Thread-7,Count:80
Thread:Thread-8,Count:90
Thread:Thread-9,Count:100




近期评论