java多线程控制:synchronized

在java中,如果开启多个线程同时读写一个对象,会导致数据不正常。为了保证数据的安全,我们会使用锁来控制线程的访问。

synchronized

synchronized,互斥锁,当一个线程持有锁时,另一个线程无法持有,只有当方法执行完,锁被释放时,其他线程才有机会获取锁。

synchronized的使用有两种方式:一种是用在方法上,一种是用在代码块上。

public synchronized void method ();

public void method () {
    synchronized(obj){
      
    }
}

当其用在方法上时,线程调用该方法会获取其实例的锁,效果等同于在代码块上锁住了自己的实例。

synchronized(this){
  
}

所以除非保证该方法的实例唯一,或者为static修饰(static修饰时,对象锁为改类的锁),否则无法保证互斥。也就是说,只能互斥同一个对象锁的线程。

wait

wait,使线程释放当前持有的对象锁,并进入等待状态,后续代码不再执行,其他线程可争夺该对象锁。

notify

notify,唤醒其他因调用其对象锁进入wait状态的线程。执行完后续代码之后释放对象锁。若有多个调用其对象进入wait状态的线程,则根据系统的实现,唤醒其中一个。

notifyAll

notifyAll,唤醒所有其他因调用其对象锁进入wait状态的线程。执行完后续代码之后释放对象锁。根据系统实现决定先唤醒哪一个。

注意

只有线程本身持有该对象锁,才能执行wait/notify/notifyAll方法,比如:

synchronized(obj){
  obj.wait();
}

不然会报异常:IllegalMonitorStateException。

死锁

有两个线程,分别持有两个对象锁,并且互相申请对方的对象锁时,会发生死锁。

比如:

synchronized(a){
  try{
    Thread.sleep(1000);
  }catch(Exception e){
    
  }
  synchronized(b){
    
  }
}


synchronized(b){
  try{
    Thread.sleep(1000);
  }catch(Exception e){
    
  }
  synchronized(a){
    
  }
}

两个线程分别持有对象锁a、b,之后互相申请对方的对象锁b、a,这个时候因为双方都无法释放自己的对象锁,同时对方无法获取对象锁,就会进入锁死BLOCKED状态。

线程可以持有多个对象锁,并且当其调用wait释放其中一个对象锁时,其扔持有其他对象锁。比如:

synchronized(a){
  
  synchronized(b){
    b.wait();
  }
}

当线程调用b的对象锁进入等待状态,并释放了对象锁b,这个时候依然保持着持有对象锁a,当此线程被唤醒并释放对象锁a之前,其他线程依然无法获取对象锁a。

你可能感兴趣的:(java多线程控制:synchronized)