2.2同步中的无限等待
静态同步锁定的是类。
-
多个对象共用一把锁
同一个类如果使用常量字符(常量字符串是存放在缓存中)串作为 synchronized(string) 对象监视器,并且对象 A 的同步方法中有死循环,那么其他对象无法调用该同步方法,表现为无限等待(其他线程被锁住)。
-
一个对象一把锁
使用局部变量的方式可以避免锁住其他线程。
因为 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");
}
}
}
死锁条件:
- 互斥(一份资源同时只能供一个线程使用)
- 占有且等待
- 不可抢占
- 循环等待
以下举例了 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);
}
}
}
}