技术学习笔记
Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode

2.2同步中的无限等待

1.静态同步与 synchronized(class)

静态同步锁定的是类。

  • 多个对象共用一把锁

    同一个类如果使用常量字符(常量字符串是存放在缓存中)串作为 synchronized(string) 对象监视器,并且对象 A 的同步方法中有死循环,那么其他对象无法调用该同步方法,表现为无限等待(其他线程被锁住)。

  • 一个对象一把锁

    使用局部变量的方式可以避免锁住其他线程。

2. synchronized 无限等待

因为 synchronized 锁定的是对象,同一个对象的方法同步执行,当一个线程执行某个方法存在死循环时,其他线程会陷入无限等待。如下,thread 与 threadB 共用一个 service 。

public class Service {
    synchronized public void service1(){
        System.out.println("service1");
        while (true){
            System.out.println("ha");
        }
    }
    synchronized public void service2(){
        System.out.println("service2");
    }
}
public class MyThread extends Thread{
    Service service;
    public MyThread(Service service){
        this.service = service;
    }
    @Override
    public void run(){
        super.run();
        service.service1();
    }
}
public class MyThreadB extends Thread{
    Service service;
    public MyThreadB(Service service){
        this.service = service;
    }
    @Override
    public void run(){
        super.run();
        service.service2();
    }
}
public class Run {
    public static void main(String[] args) {
        Service service = new Service();//two threads use the same service. 
        MyThread myThread = new MyThread(service);
        myThread.start();
        MyThreadB myThreadB = new MyThreadB(service);
        myThreadB.start();
    }
}

解决方法:同步块并且对象监视器使用不同对象。一个方法对应一个对象监视器,做到单个方法的同步(锁住单个方法)。

public class Service {
    Object object = new Object();
    public void service1(){
        synchronized(object){
            System.out.println("service1");
            while (true){
                System.out.println("ha");
            }
        }
    }
    Object object1 = new Object();
    public void service2(){
        synchronized (object1){
            System.out.println("service2");
        }
    }
}

3. 多线程死锁

死锁条件:

  • 互斥(一份资源同时只能供一个线程使用)
  • 占有且等待
  • 不可抢占
  • 循环等待

以下举例了 4 秒钟的死锁,线程占有的时间越长,死锁时间越长。

public class DealThread implements Runnable{
    public String username;
    public Object lock1 = new Object();
    public Object lock2 = new Object();
    public void setFlag(String username){
        this.username = username;
    }
    @Override
    public void run(){
        if (username.equals("a")){
            synchronized (lock1){
                System.out.println("username: " + username);
                try{
                    Thread.sleep(4000);//4 second dead lock
                }catch(Exception e){
                    e.printStackTrace();
                }
            }
            synchronized (lock2){
                System.out.println("lock2 username: "  + username);
            }
        }else if(username.equals("b")){
            synchronized (lock2){
                System.out.println("username: " + username);
                try{
                    Thread.sleep(4000);//4 second dead lock
                }catch(Exception e){
                    e.printStackTrace();
                }
            }
            synchronized (lock1){
                System.out.println("lock1 username: "  + username);
            }
        }
    }

}