线程安全导致效率降低
采用多把锁方式
采用多把锁的前提,是两个共享资源之前没有关联性。
- 好处:可以增强并发度
- 坏处:如果一个线程需要同时获得多把锁,容易产生死锁
线程安全带来线程活跃性问题
死锁
- 一个线程需要同时获取多吧锁,容易产生死锁
- 线程1已经获得锁A,需要获得锁B
- 线程2已经获得锁B,需要获得锁A
- 可以采取顺序加锁方式,解决线程死锁问题
- 检测定位死锁
- jconsole
- jstack
- 典型问题:哲学家就餐
public class PhilosopherProblem {
public static void main(String[] args) {
Chopstic c1 = new Chopstic("1");
Chopstic c2 = new Chopstic("2");
Chopstic c3 = new Chopstic("3");
Chopstic c4 = new Chopstic("4");
Chopstic c5 = new Chopstic("5");
new Philosopher("苏格拉底",c1,c2).start();
new Philosopher("泊拉图",c2,c3).start();
new Philosopher("亚里士多德",c3,c4).start();
new Philosopher("阿基米德",c4,c5).start();
new Philosopher("米开朗琪罗",c5,c1).start();
}
}
@Slf4j(topic = "ants.Philosopher")
class Philosopher extends Thread{
Chopstic left;
Chopstic right;
public Philosopher(String name,Chopstic left,Chopstic right){
super(name);
this.left = left;
this.right = right;
}
@SneakyThrows
@Override
public void run() {
while (true){
synchronized (left){
synchronized (right){
eat();
}
}
}
}
private void eat() throws InterruptedException {
log.debug("eating...");
Thread.sleep(1000);
}
}
class Chopstic{
private String name;
public Chopstic(String name){
this.name = name;
}
@Override
public String toString() {
return "筷子:【"+name+"】";
}
}
线程执行一段时间后不再向下执行,这时候发生死锁,分析如下
使用jps查看线程
...... jps
593 Launcher
594 PhilosopherProblem
548
621 Jps
使用jstack 594查看线程运行情况,发现死锁
Found one Java-level deadlock:
活锁
- 两个线程,互相修改对方的结束条件
- 解决活锁:破坏活锁发生条件,例如随机的随眠时间
@Slf4j(topic = "ants.LiveLock")
public class LiveLock {
static volatile int i=10;
public static void main(String[] args) {
new Thread("t1"){
boolean flag = true;
@Override
public void run() {
while (true){
log.debug(i+"");
i--;
if(i==0){
flag=false;
log.debug("线程1执行完毕");
}
}
}
}.start();
new Thread("t2"){
boolean flag = true;
@Override
public void run() {
while (true){
log.debug(i+"");
i++;
if(i==20){
flag=false;
log.debug("线程2执行完毕");
}
}
}
}.start();
}
}
饥饿
- 一个线程由于优先级太低,始终得不到CPU调度执行,不能够结束
网友评论