Synchronized几种不同的同步方法、脏读、死锁代码样例讲解

it2024-03-25  79

1. 方法内的变量不存在非线程安全问题,永远都是线程安全的,这是因为方法内部的变量具有私有特性,不需要使用同步。

2. 当两个线程同时访问同一个业务对象中的没有同步的方法,并且同时操作业务对象中的实例变量,则有可能出现非线程安全问题。

例子如下

public class SynchronizedTest2 { public static void main(String[] args) { HasSelfPrivateNum numRef = new HasSelfPrivateNum(); ThreadA aThread = new ThreadA(numRef); aThread.start(); ThreadB bThread = new ThreadB(numRef); bThread.start(); } static class HasSelfPrivateNum{ private int num = 0; public void addI(String name) { try { if("a".equals(name)) { num = 100; System.out.println("a set over!"); Thread.sleep(2000); }else { num = 200; System.out.println("b set over!"); } System.out.println(name + "num=" + num); }catch (InterruptedException e) { e.printStackTrace(); } } } static class ThreadA extends Thread{ private HasSelfPrivateNum numRef; public ThreadA(HasSelfPrivateNum numRef) { super(); this.numRef = numRef; } @Override public void run() { super.run(); numRef.addI("a"); } } static class ThreadB extends Thread{ private HasSelfPrivateNum numRef; public ThreadB(HasSelfPrivateNum numRef) { super(); this.numRef = numRef; } @Override public void run() { super.run(); numRef.addI("b"); } } }

运行结果为

a set over! b set over! bnum=200 anum=200

3. 如果业务对象和锁对象是属于一对一的关系,每个线程执行自己所属业务对象中的同步方法,不存在争抢关系,也是不需要锁的。

例子如下

public class SynchronizedTest3 { public static void main(String[] args) { HasSelfPrivateNum numRefA = new HasSelfPrivateNum(); HasSelfPrivateNum numRefB = new HasSelfPrivateNum(); ThreadA aThread = new ThreadA(numRefA); aThread.start(); ThreadB bThread = new ThreadB(numRefB); bThread.start(); } static class HasSelfPrivateNum{ private int num = 0; synchronized public void addI(String name) { try { if("a".equals(name)) { num = 100; System.out.println("a set over!"); Thread.sleep(2000); }else { num = 200; System.out.println("b set over!"); } System.out.println(name + "num=" + num); }catch (InterruptedException e) { e.printStackTrace(); } } } static class ThreadA extends Thread{ private HasSelfPrivateNum numRef; public ThreadA(HasSelfPrivateNum numRef) { super(); this.numRef = numRef; } @Override public void run() { super.run(); numRef.addI("a"); } } static class ThreadB extends Thread{ private HasSelfPrivateNum numRef; public ThreadB(HasSelfPrivateNum numRef) { super(); this.numRef = numRef; } @Override public void run() { super.run(); numRef.addI("b"); } } }

运行结果为

a set over! b set over! bnum=200 anum=100

4. 两个线程访问同一个对象的两个方法

此时有以下结论

A线程现持有object对象的Lock锁,B线程可以以异步的方式调用object对象中的非synchronized类型的方法。A线程先持有object对象的Lock锁,B线程如果在这时调用object对象中的synchronized类型的方法,则需要等待,也就是同步。在方法声明处添加synchronized并不是锁方法,而是锁当前类的对象。在Java中只有“当对象作为锁”这种说法,并没有“锁方法”这种说法。在Java语言中,“锁”就是“对象”,“对象”可以映射成“锁”,哪个线程拿到这把锁,哪个线程就可以执行这个对象中的synchronized同步方法。如果在对象中使用了synchronized关键字声明非静态方法,则对象就被当成锁。

例子1:两个线程分别调用同一个对象的同步方法和非同步方法

public class SynchronizedTest4_1 { public static void main(String[] args) { MyObject obejct = new MyObject(); ThreadA aThread = new ThreadA(obejct); aThread.start(); ThreadB bThread = new ThreadB(obejct); bThread.start(); } static class MyObject{ synchronized public void methodA() { try { System.out.println("begin methodA threadName=" + Thread.currentThread().getName()); Thread.sleep(5000); System.out.println("end endTime=" + System.currentTimeMillis()); }catch (InterruptedException e) { e.printStackTrace(); } } public void methodB() { try { System.out.println("begin methodB threadName=" + Thread.currentThread().getName()); Thread.sleep(5000); System.out.println("end endTime=" + System.currentTimeMillis()); }catch (InterruptedException e) { e.printStackTrace(); } } } static class ThreadA extends Thread{ private MyObject object; public ThreadA(MyObject object) { super(); this.object = object; } @Override public void run() { super.run(); object.methodA(); } } static class ThreadB extends Thread{ private MyObject object; public ThreadB(MyObject object) { super(); this.object = object; } @Override public void run() { super.run(); object.methodB(); } } }

运行结果为

begin methodA threadName=Thread-0 begin methodB threadName=Thread-1 end endTime=1603249231399 end endTime=1603249231399

例子2:两个线程分别调用同一个对象的两个不同的同步方法

public class SynchronizedTest4_2 { public static void main(String[] args) { MyObject obejct = new MyObject(); ThreadA aThread = new ThreadA(obejct); aThread.start(); ThreadB bThread = new ThreadB(obejct); bThread.start(); } static class MyObject{ synchronized public void methodA() { try { System.out.println("begin methodA threadName=" + Thread.currentThread().getName()); Thread.sleep(5000); System.out.println("end endTime=" + System.currentTimeMillis()); }catch (InterruptedException e) { e.printStackTrace(); } } synchronized public void methodB() { try { System.out.println("begin methodB threadName=" + Thread.currentThread().getName()); Thread.sleep(5000); System.out.println("end endTime=" + System.currentTimeMillis()); }catch (InterruptedException e) { e.printStackTrace(); } } } static class ThreadA extends Thread{ private MyObject object; public ThreadA(MyObject object) { super(); this.object = object; } @Override public void run() { super.run(); object.methodA(); } } static class ThreadB extends Thread{ private MyObject object; public ThreadB(MyObject object) { super(); this.object = object; } @Override public void run() { super.run(); object.methodB(); } } }

运行结果为:

begin methodA threadName=Thread-0 end endTime=1603249500001 begin methodB threadName=Thread-1 end endTime=1603249505002

5. 脏读

我们有时候在赋值的方法进行了同步,但是在取值的方法没有进行同步,就有可能出现脏读(dirty read) 例子:

public class SynchronizedTest5 { public static void main(String[] args) { PublicVar publicVar = new PublicVar(); ThreadA aThread = new ThreadA(publicVar); aThread.start(); ThreadB bThread = new ThreadB(publicVar); bThread.start(); } static class PublicVar{ public String username = "A"; public String password = "AA"; synchronized public void setValue(String username, String password) { try { this.username = username; Thread.sleep(5000); this.password = password; System.out.println("setValue method thread name=" + Thread.currentThread().getName() + " username" + username + " password=" + password); }catch (InterruptedException e) { e.printStackTrace(); } } public void getValue() { System.out.println("getValue method thread name=" + Thread.currentThread().getName() + " username" + username + " password=" + password); } } static class ThreadA extends Thread{ private PublicVar publicVar; public ThreadA(PublicVar publicVar) { super(); this.publicVar = publicVar; } @Override public void run() { super.run(); publicVar.setValue("B", "BB"); } } static class ThreadB extends Thread{ private PublicVar publicVar; public ThreadB(PublicVar publicVar) { super(); this.publicVar = publicVar; } @Override public void run() { super.run(); publicVar.getValue(); } } }

运行结果为:

getValue method thread name=Thread-1 usernameB password=AA setValue method thread name=Thread-0 usernameB password=BB

6. Synchronized锁重入

“可重入锁”是指自己可以再次获取自己的内部锁。例如。一个线程获得了某个对象锁,此时这个对象锁还没有释放,当其再次想要获取这个对象锁时还是可以获取的。 并且锁重入支持继承的环境 例子

public class SynchronizedTest6 { public static void main(String[] args) { MyThreadA t1 = new MyThreadA(); t1.start(); MyThreadB t2 = new MyThreadB(); t2.start(); } static class Main{ public int i = 10; synchronized public void operateIMainMethod() { try { i--; System.out.println("main pint i=" + i); Thread.sleep(100); }catch (InterruptedException e) { e.printStackTrace(); } } } static class Sub extends Main{ public int i = 10; synchronized public void operateISubMethod() { try { i--; System.out.println("sub pint i=" + i); Thread.sleep(1000); super.operateIMainMethod(); }catch (InterruptedException e) { e.printStackTrace(); } } } static class Sub2 extends Main{ public int i = 10; synchronized public void operateISubMethod() { try { i--; System.out.println("sub2 pint i=" + i); Thread.sleep(1000); super.operateIMainMethod(); }catch (InterruptedException e) { e.printStackTrace(); } } } static class MyThreadA extends Thread{ @Override public void run() { Sub sub = new Sub(); sub.operateISubMethod(); } } static class MyThreadB extends Thread{ @Override public void run() { Sub2 sub2 = new Sub2(); sub2.operateISubMethod(); } } }

运行结果

sub pint i=9 sub2 pint i=9 main pint i=9 main pint i=9

7. 出现异常,锁会自动释放

当一个线程执行的代码出现异常时,其所持有的锁会自动释放。Thread.java类中suspend()方法和sleep(millis)方法被调用后并不释放锁。

8. 重写方法

重写方法如果不使用synchronized关键字,即是非同步方法,使用后变成同步方法。

9. 单一方法内的sychronized同步语句块

用关键字synchronized声明方法在某些情况下是有弊端的,例如:A线程调用同步方法执行一个长时间的任务,那么B线程等待的时间就比较长,这种情况可以使用synchronized同步语句块来解决,以提高运行效率。此时只有运行到同步语句块的时候才会需要获取锁,方法内的其他代码都不需要锁。 例子1:synchronized声明方法

public class Task{ public String getData1; public String getData2; synchronized public void doLongTimeTask() { try { System.out.println("begin task"); Thread.sleep(3000); getData1 = "长时间处理任务后从远程返回的值1 threadName=" + Thread.currentThread().getName(); getData2 = "长时间处理任务后从远程返回的值2 threadName=" + Thread.currentThread().getName(); System.out.println(getData1); System.out.println(getData2); System.out.println("end task"); }catch (InterruptedException e) { e.printStackTrace(); } } }

例子2:synchronized同步语句块

static class Task{ public String getData1; public String getData2; public void doLongTimeTask() { try { System.out.println("begin task"); Thread.sleep(3000); synchronized(this) { getData1 = "长时间处理任务后从远程返回的值1 threadName=" + Thread.currentThread().getName(); getData2 = "长时间处理任务后从远程返回的值2 threadName=" + Thread.currentThread().getName(); System.out.println(getData1); System.out.println(getData2); System.out.println("end task"); } }catch (InterruptedException e) { e.printStackTrace(); } } }

10. 多个synchronized同步语句块

在使用同步synchronized(this)代码块时需要注意,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对同一个object中所有其他synchronized(this)同步代码块的访问将被阻塞。 我们常用的PrintStream.println方法也是使用的同步代码块。

11. synchronized同步语句块和synchronized修饰的方法

使用synchronized(this)同步代码块将当前类的对象作为锁,使用synchronized修饰的方法也是将当前类所在的对象作为锁,都是同一把锁,所以会相互阻塞。 例子

public class SynchronizedTest11 { public static void main(String[] args) { Task task = new Task(); ThreadA aThread = new ThreadA(task); aThread.start(); ThreadB bThread = new ThreadB(task); bThread.start(); } static class Task{ public void doLongTimeTask() { try { synchronized(this) { System.out.println("=======run===doLongTimeTask====start"); Thread.sleep(5000); System.out.println("=======run===doLongTimeTask====end"); } }catch (InterruptedException e) { e.printStackTrace(); } } synchronized public void otherMethod() { System.out.println("-----run---otherMethod"); } } static class ThreadA extends Thread{ private Task task; public ThreadA(Task task) { super(); this.task = task; } @Override public void run() { super.run(); task.doLongTimeTask(); } } static class ThreadB extends Thread{ private Task task; public ThreadB(Task task) { super(); this.task = task; } @Override public void run() { super.run(); task.otherMethod(); } } }

运行结果:

=======run===doLongTimeTask====start =======run===doLongTimeTask====end -----run---otherMethod

12. 将任意对象作为锁

多个线程调用同一个对象中的不同名称的synchronized同步方法或synchronzied(this)同步代码块时,调用的效果都是按顺序执行,即同步。 synchronized同步代码块和synchronized同步方法基本一样,都是下面两个规则:

对于其他synchronized同步方法或synchronized(this)同步代码块调用呈同步效果同一时间只有一个线程可以执行synchronized同步方法(synchronized同步代码块)中的代码

除了使用synchronized(this)格式来创建同步代码块,其实Java还支持将“任意对象”作为锁来实现同步的功能,这个“任意对象”大多数是实例变量及方法的参数。使用格式为synchronized(非this对象)。 synchronized(非this对象X)同步代码的作用:当多个线程争抢相同的“非this对象X”的锁时,同一时间只有一个线程可以执行synchronized(非this对象X)同步代码块中的代码。 例子:

public class SynchronizedTest12 { public static void main(String[] args) { Service service = new Service(); ThreadA aThread = new ThreadA(service); aThread.start(); ThreadB bThread = new ThreadB(service); bThread.start(); } static class Service{ private String anyString = new String(); public void a() { try { synchronized(anyString) { System.out.println("in synchronized anyString, threadName=" + Thread.currentThread().getName()); Thread.sleep(5000); System.out.println("exit synchronized anyString, threadName=" + Thread.currentThread().getName()); } }catch (InterruptedException e) { e.printStackTrace(); } } } static class ThreadA extends Thread{ private Service service; public ThreadA(Service service) { super(); this.service = service; } @Override public void run() { super.run(); service.a(); } } static class ThreadB extends Thread{ private Service service; public ThreadB(Service service) { super(); this.service = service; } @Override public void run() { super.run(); service.a(); } } }

运行结果:

in synchronized anyString, threadName=Thread-0 exit synchronized anyString, threadName=Thread-0 in synchronized anyString, threadName=Thread-1 exit synchronized anyString, threadName=Thread-1

13. 同一个对象中的不同锁

如果synchronized(对象X)中的对象不是同一个对象,那么即便在同一个对象锁,也不会产生锁竞争。 例子:

public class SynchronizedTest13 { public static void main(String[] args) { Service service = new Service(); ThreadA aThread = new ThreadA(service); aThread.start(); ThreadB bThread = new ThreadB(service); bThread.start(); } static class Service{ private String anyString = new String(); public void a() { try { synchronized(anyString) { System.out.println("in a, threadName=" + Thread.currentThread().getName()); Thread.sleep(5000); System.out.println("exit a, threadName=" + Thread.currentThread().getName()); } }catch (InterruptedException e) { e.printStackTrace(); } } synchronized public void b() { System.out.println("in b, threadName=" + Thread.currentThread().getName()); } } static class ThreadA extends Thread{ private Service service; public ThreadA(Service service) { super(); this.service = service; } @Override public void run() { super.run(); service.a(); } } static class ThreadB extends Thread{ private Service service; public ThreadB(Service service) { super(); this.service = service; } @Override public void run() { super.run(); service.b(); } } }

运行结果:

in a, threadName=Thread-0 in b, threadName=Thread-1 exit a, threadName=Thread-0

14. 方法被调用时随机的

同步代码块放在非同步synchronized方法中进行声明,并不能保证调用方法的线程的执行同步顺序性,也就是线程调用方法的顺序是无序的,虽然在同步块中执行的顺序是同步的。 例子:

public class SynchronizedTest14 { public static void main(String[] args) { MyList list = new MyList(); ThreadA aThread = new ThreadA(list); aThread.setName("A"); aThread.start(); ThreadB bThread = new ThreadB(list); bThread.setName("B"); bThread.start(); } static class MyList{ synchronized public void add(String username) { System.out.println("in add,threadName=" + Thread.currentThread().getName()); System.out.println("exit add,threadName=" + Thread.currentThread().getName()); } } static class ThreadA extends Thread{ private MyList list; public ThreadA(MyList list) { super(); this.list = list; } @Override public void run() { super.run(); for(int i = 1; i < 1000; i++) { list.add("threadA" + i); } } } static class ThreadB extends Thread{ private MyList list; public ThreadB(MyList list) { super(); this.list = list; } @Override public void run() { super.run(); for(int i = 1; i < 1000; i++) { list.add("threadB" + i); } } } }

运行结果太过于长,只截取部分

in add,threadName=A exit add,threadName=A in add,threadName=A exit add,threadName=A in add,threadName=A exit add,threadName=A in add,threadName=B exit add,threadName=B in add,threadName=B exit add,threadName=B in add,threadName=A exit add,threadName=A in add,threadName=A exit add,threadName=A in add,threadName=B exit add,threadName=B in add,threadName=A exit add,threadName=A

15. 不同步导致的逻辑错误

有些方法不进行同步化,则会出现逻辑上的错误 例子如下:

public class SynchronizedTest15 { public static void main(String[] args) throws InterruptedException { MyOneList list = new MyOneList(); ThreadA aThread = new ThreadA(list); aThread.setName("A"); aThread.start(); ThreadB bThread = new ThreadB(list); bThread.setName("B"); bThread.start(); Thread.sleep(6000); System.out.println("listSize=" + list.getSize()); } static class MyOneList{ private List<String> list = new ArrayList<String>(); synchronized public void add(String data) { list.add(data); } synchronized public int getSize() { return list.size(); } } static class MyService{ public MyOneList addServiceMethod(MyOneList list, String data) { try { if(list.getSize() < 1) { Thread.sleep(2000); list.add(data); } } catch (InterruptedException e) { e.printStackTrace(); } return list; } } static class ThreadA extends Thread{ private MyOneList list; public ThreadA(MyOneList list) { super(); this.list = list; } @Override public void run() { super.run(); MyService msRef = new MyService(); msRef.addServiceMethod(list, "A"); } } static class ThreadB extends Thread{ private MyOneList list; public ThreadB(MyOneList list) { super(); this.list = list; } @Override public void run() { super.run(); MyService msRef = new MyService(); msRef.addServiceMethod(list, "B"); } } }

运行结果为

listSize=2

这就是没有对MyService.addServiceMethod()方法进行同步导致的错误

16. 静态同步方法synchronized方法和synchronized(class)代码块

关键字synchronized还可以应用在static静态方法上,如果这样写,那是对当前的*.java文件对应的Class类对象进行持锁,Class类的对象是单例的,更具体的说,在静态static方法上使用synchronized关键字声明同步方法时,使用当前静态方法所在类对应Class类的单例对象作为锁。 例子1:静态同步方法和非静态同步方法是不同的锁

public class SynchronizedTest16 { public static void main(String[] args) throws InterruptedException { Service service = new Service(); ThreadA aThread = new ThreadA(service); aThread.setName("A"); aThread.start(); ThreadB bThread = new ThreadB(service); bThread.setName("B"); bThread.start(); } static class Service{ synchronized public static void printA() { try { System.out.println("in A ,threadName=" + Thread.currentThread().getName()); Thread.sleep(3000); System.out.println("exit A ,threadName=" + Thread.currentThread().getName()); } catch (InterruptedException e) { e.printStackTrace(); } } synchronized public void printB() { try { System.out.println("in B ,threadName=" + Thread.currentThread().getName()); Thread.sleep(3000); System.out.println("exit B ,threadName=" + Thread.currentThread().getName()); } catch (InterruptedException e) { e.printStackTrace(); } } } static class ThreadA extends Thread{ private Service service; public ThreadA(Service service) { super(); this.service = service; } @Override public void run() { super.run(); service.printA(); } } static class ThreadB extends Thread{ private Service service; public ThreadB(Service service) { super(); this.service = service; } @Override public void run() { super.run(); service.printB(); } } }

运行结果

in A ,threadName=A in A ,threadName=B exit A ,threadName=B exit A ,threadName=A

例子2:同一个类的不同对象的不同synchronized静态方法也是同一把锁

public class SynchronizedTest16_2 { public static void main(String[] args) throws InterruptedException { Service service1 = new Service(); ThreadA aThread = new ThreadA(service1); aThread.setName("A"); aThread.start(); Service service2 = new Service(); ThreadB bThread = new ThreadB(service2); bThread.setName("B"); bThread.start(); } static class Service{ synchronized public static void printA() { try { System.out.println("in A ,threadName=" + Thread.currentThread().getName()); Thread.sleep(3000); System.out.println("exit A ,threadName=" + Thread.currentThread().getName()); } catch (InterruptedException e) { e.printStackTrace(); } } synchronized public static void printB() { try { System.out.println("in B ,threadName=" + Thread.currentThread().getName()); Thread.sleep(3000); System.out.println("exit B ,threadName=" + Thread.currentThread().getName()); } catch (InterruptedException e) { e.printStackTrace(); } } } static class ThreadA extends Thread{ private Service service; public ThreadA(Service service) { super(); this.service = service; } @Override public void run() { super.run(); service.printA(); } } static class ThreadB extends Thread{ private Service service; public ThreadB(Service service) { super(); this.service = service; } @Override public void run() { super.run(); service.printB(); } } }

运行结果

in A ,threadName=A exit A ,threadName=A in B ,threadName=B exit B ,threadName=B

例子3:synchronized静态方法和synchronized(Class)是同一把锁

public class SynchronizedTest16_3 { public static void main(String[] args) throws InterruptedException { Service service1 = new Service(); ThreadA aThread = new ThreadA(service1); aThread.setName("A"); aThread.start(); Service service2 = new Service(); ThreadB bThread = new ThreadB(service2); bThread.setName("B"); bThread.start(); } static class Service{ synchronized public static void printA() { try { System.out.println("in A ,threadName=" + Thread.currentThread().getName()); Thread.sleep(3000); System.out.println("exit A ,threadName=" + Thread.currentThread().getName()); } catch (InterruptedException e) { e.printStackTrace(); } } public void printB() { try { synchronized(Service.class) { System.out.println("in B ,threadName=" + Thread.currentThread().getName()); Thread.sleep(3000); System.out.println("exit B ,threadName=" + Thread.currentThread().getName()); } } catch (InterruptedException e) { e.printStackTrace(); } } } static class ThreadA extends Thread{ private Service service; public ThreadA(Service service) { super(); this.service = service; } @Override public void run() { super.run(); service.printA(); } } static class ThreadB extends Thread{ private Service service; public ThreadB(Service service) { super(); this.service = service; } @Override public void run() { super.run(); service.printB(); } } }

运行结果

in A ,threadName=A exit A ,threadName=A in B ,threadName=B exit B ,threadName=B

17. String常量池特性和同步相关问题

JVM具有String常量池的功能,当synchronized(string)同步块与String联合使用时,要注意常量池带来的一些意外。 当你传入的String的值是一样的时候,锁可能就是相同的。 例子

public class SynchronizedTest17 { public static void main(String[] args) throws InterruptedException { Service service = new Service(); ThreadA aThread = new ThreadA(service); aThread.setName("A"); aThread.start(); ThreadB bThread = new ThreadB(service); bThread.setName("B"); bThread.start(); } static class Service{ public static void print(String stringParam) { try { synchronized(stringParam) { while(true) { System.out.println("in print,threadName=" + Thread.currentThread().getName()); Thread.sleep(1000); System.out.println("exit print,threadName=" + Thread.currentThread().getName()); } } } catch (InterruptedException e) { e.printStackTrace(); } } } static class ThreadA extends Thread{ private Service service; public ThreadA(Service service) { super(); this.service = service; } @Override public void run() { super.run(); service.print("AA"); } } static class ThreadB extends Thread{ private Service service; public ThreadB(Service service) { super(); this.service = service; } @Override public void run() { super.run(); service.print("AA"); } } }

截取部分运行结果:

in print,threadName=A exit print,threadName=A in print,threadName=A exit print,threadName=A in print,threadName=A exit print,threadName=A in print,threadName=A exit print,threadName=A in print,threadName=A exit print,threadName=A in print,threadName=A exit print,threadName=A in print,threadName=A exit print,threadName=A

18. 多线程的死锁

Java线程死锁是一个经典的多线程问题,因为不同的线程都在等待根本不可能被释放的锁,从而导致所有的任务都无法继续完成。在多线程技术中,“死锁”是必须避免的,因为这会造成线程“假死”。 例子:

public class SynchronizedTest18 { public static void main(String[] args) throws InterruptedException { DealThread t1 = new DealThread(); t1.setFlag("a"); Thread thread1 = new Thread(t1); thread1.start(); Thread.sleep(1000); t1.setFlag("b"); Thread thread2 = new Thread(t1); thread2.start(); } static 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("a".equals(username)) { synchronized (lock1) { try { System.out.println("username= " + username); Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } synchronized(lock2) { System.out.println("按lock1->lock2代码顺序执行了"); } } } if("b".equals(username)) { synchronized (lock2) { try { System.out.println("username= " + username); Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } synchronized(lock1) { System.out.println("按lock2->lock1代码顺序执行了"); } } } } } }

运行结果

username= a username= b

总结

最新回复(0)