当一个synchronized关键字修饰的方法同时又被static修饰,之前说过,非静态的同步方法会将对象上锁,但是静态方法不属于对象,而是属于类,它会将这个方法所在的类的Class对象上锁。
一个类不管生成多少个对象,它们所对应的是同一个Class对象。
1 public class ThreadTest 2 { 3 public static void main(String[] args) 4 { 5 Example example = new Example(); 6 7 Thread t1 = new Thread1(example); 8 9 // 此处即便传入不同的对象,静态方法同步仍然不允许多个线程同时执行 10 example = new Example(); 11 12 Thread t2 = new Thread2(example); 13 14 t1.start(); 15 t2.start(); 16 } 17 18 } 19 20 class Example 21 { 22 public synchronized static void execute() 23 { 24 for (int i = 0; i < 20; ++i) 25 { 26 try 27 { 28 Thread.sleep((long) Math.random() * 1000); 29 } 30 catch (InterruptedException e) 31 { 32 e.printStackTrace(); 33 } 34 System.out.println("Hello: " + i); 35 } 36 } 37 38 public synchronized static void execute2() 39 { 40 for (int i = 0; i < 20; ++i) 41 { 42 try 43 { 44 Thread.sleep((long) Math.random() * 1000); 45 } 46 catch (InterruptedException e) 47 { 48 e.printStackTrace(); 49 } 50 System.out.println("World: " + i); 51 } 52 } 53 54 } 55 56 class Thread1 extends Thread 57 { 58 private Example example; 59 60 public Thread1(Example example) 61 62 { 63 this.example = example; 64 } 65 66 @Override 67 public void run() 68 { 69 Example.execute(); 70 } 71 72 } 73 74 class Thread2 extends Thread 75 { 76 private Example example; 77 78 public Thread2(Example example) 79 { 80 this.example = example; 81 } 82 83 @Override 84 public void run() 85 { 86 Example.execute2(); 87 } 88 89 }
所以如果是静态方法的情况(execute()和execute2()都加上static关键字),即便是向两个线程传入不同的Example对象,这两个线程仍然是互相制约的,必须先执行完一个,再执行下一个。
结论:
如果某个synchronized方法是static的,那么当线程访问该方法时,它锁的并不是synchronized方法所在的对象,而是synchronized方法所在的类所对应的Class对象。Java中,无论一个类有多少个对象,这些对象会对应唯一一个Class对象,因此当线程分别访问同一个类的两个对象的两个static,synchronized方法时,它们的执行顺序也是顺序的,也就是说一个线程先去执行方法,执行完毕后另一个线程才开始。