多线程浅析(三)
Java中多线程在运行的时候,由于我们给线程加上同步锁,而我们又弄混了多线程运行的先后顺序以及关系,可能会出现死锁的现象;在这里讨论一下Java多线程死锁的两种情况。
死锁的两种情况
–>1:程序中有多个线程,且线程之间共用同一个对象锁,线程之间互相等待!
代码演示:
/*
*Client.java
*/
public class Client {
public static void main(String[] args) {
S s=new S();
Thread b=new Thread(new ThreadB(s));
ThreadA a=new ThreadA(s,b);
b.start();
a.start();
}
}
//锁
class S{
public int a=1;
}
---------------------------------------------------------------
/*
*ThreadB.java
*这里是通过实现Runnable接口的方式
*/
public class ThreadB implements Runnable{
private S s=null;
public ThreadB(S s){
this.s=s;
}
@Override
public void run() {
System.out.println("B线程开始");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("B线程睡眠时间到,醒来继续运行");
synchronized (s) {
s.a=100;
System.out.println("B线程已完成对a的赋值,a="+s.a);
}
}
}
---------------------------------------------------------------
/*
*ThreadA.java
*这里是通过继承Thread类的方式
*/
public class ThreadA extends Thread{
private S s=null;
private Thread b=null;
public ThreadA(S s,Thread b){
this.s=s;
this.b=b;
}
@Override
public void run() {
System.out.println("A线程开始");
synchronized (s){
System.out.println("A线程拿到对象锁,进入同步块");
try {
b.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("A线程,a="+s.a);
}
}
}
我对这种情况的死锁的理解:其实就是有很多线程共享一个对象锁,当一个线程拿到对象锁之后却想让其它也需要同一个对象锁的线程先运行,而其它线程又因为拿不到对象锁而一直等待 ,所以就出现了死锁。
–>2:程序中有多个线程,也有多个对象锁,每个线程都需要拿到不止一个锁,而多个线程都处于:各持有一部分锁或资源,都等待另一部分的情况,就会出现死锁。
代码演示:
/*
*Client.java
*/
public class Client {
public static void main(String[] args) {
S1 s1=new S1();
S2 s2=new S2();
Thread b=new Thread(new ThreadB(s1,s2));
Thread a=new Thread(new ThreadA(s1,s2));
b.start();
a.start();
}
}
//锁
class S1{
public int a=1;
}
class S2{
public int b=2;
}
---------------------------------------------------------------
/*
*ThreadB.java
*这里是实现Runnable接口的方式
*/
public class ThreadB implements Runnable{
private S1 s1=null;
private S2 s2=null;
public ThreadB(S1 s1,S2 s2){
this.s1=s1;
this.s2=s2;
}
@Override
public void run() {
System.out.println("B线程开始运行");
synchronized (s2) {//拿到对象锁2
try {
Thread.sleep(1000);//线程睡眠
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("睡眠时间到,B线程继续运行");
synchronized (s1) {
System.out.println("B线程拿到对象锁1和2,准备工作");
}
}
}
}
---------------------------------------------------------------
/*
*ThreadA.java
*这里是继承Thread类的方式
*/
public class ThreadA extends Thread{
private S1 s1=null;
private S2 s2=null;
public ThreadA(S1 s1,S2 s2){
this.s1=s1;
this.s2=s2;
}
@Override
public void run() {
System.out.println("A线程开始运行");
synchronized (s1) {//拿到对象锁1
try {
Thread.sleep(1000);//线程睡眠
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("睡眠时间到,A线程继续运行");
synchronized (s2) {
System.out.println("A线程拿到对象锁1和对象锁2,准备工作");
}
}
}
}
我对这种死锁的理解:就是有很多线程,每个线程都需要很多的资源,就有可能出现一个线程拿到一部分资源,而另一个线程拿到了另一部分资源,互相等待对方先释放资源,就出现了死锁。
平时多线程的时候要多注意弄清线程和锁之间的关系,尽量避免死锁的出现,否则对会极大的阻碍程序的运行,加深内耗,有几点对死锁的建议:
1.从设计的角度就要避免死锁,即在设计线程和锁之间的关系时要注意
2.尽量减少程序中的临界资源,改变线程临界资源的获取方式
就这些吧!