Java的synchronized可以加在方法上,也可以直接加在对象上,从而保证一段代码只能有一个线程在运行,保证线程的同步。
那么这两者究竟有啥区别呢?我们可以看下面的示例代码。
001 | public class SyncTest { |
002 |
003 | public static synchronized void testSyncOnStaticMethod() { |
004 | System.out.println( "testSyncOnStaticMethod" ); |
005 | try { |
006 | Thread.sleep( 10000 ); |
007 | } catch (InterruptedException e) { |
008 | } |
009 | } |
010 |
011 | public static void testSyncOnClass() { |
012 | synchronized (SyncTest. class ) { |
013 | System.out.println( "testSyncOnClass" ); |
014 | try { |
015 | Thread.sleep( 10000 ); |
016 | } catch (InterruptedException e) { |
017 | } |
018 | } |
019 | } |
020 |
021 | public synchronized void testSyncOnMethod() { |
022 | System.out.println( "testSyncOnMethod" ); |
023 | try { |
024 | Thread.sleep( 10000 ); |
025 | } catch (InterruptedException e) { |
026 | } |
027 | } |
028 |
029 | public void testSyncOnThis() { |
030 | synchronized ( this ) { |
031 | System.out.println( "testSyncOnThis" ); |
032 | try { |
033 | Thread.sleep( 10000 ); |
034 | } catch (InterruptedException e) { |
035 | } |
036 | } |
037 | } |
038 |
039 | public static void case1() { |
040 | // case1 |
041 | // 先输出testSyncOnThis或者testSyncOnMethod |
042 | // 然后停顿10秒,再输出另一个 |
043 | // 这个现象表明了 |
044 | |
045 | // public synchronized void func() { |
046 | // } |
047 | |
048 | // 等价于 |
049 | |
050 | // public void func() { |
051 | // synchronized (this) { |
052 | // } |
053 | // } |
054 | final SyncTest t1 = new SyncTest(); |
055 | new Thread( new Runnable() { |
056 |
057 | @Override |
058 | public void run() { |
059 | t1.testSyncOnThis(); |
060 | } |
061 | }).start(); |
062 |
063 | new Thread( new Runnable() { |
064 |
065 | @Override |
066 | public void run() { |
067 | t1.testSyncOnMethod(); |
068 | } |
069 | }).start(); |
070 | } |
071 |
072 | public static void case2() { |
073 | // case2 |
074 | // 先输出testSyncOnClass或者testSyncOnStaticMethod |
075 | // 然后停顿10秒,再输出另一个 |
076 | // 这个现象表明了 |
077 | |
078 | // public synchronized static void staticFunc() { |
079 | // } |
080 | |
081 | // 等价于 |
082 | |
083 | // public static void staticFunc() { |
084 | // synchronized (SyncTest.class) { |
085 | // } |
086 | // } |
087 | new Thread( new Runnable() { |
088 |
089 | @Override |
090 | public void run() { |
091 | SyncTest.testSyncOnClass(); |
092 | } |
093 | }).start(); |
094 |
095 | new Thread( new Runnable() { |
096 |
097 | @Override |
098 | public void run() { |
099 | SyncTest.testSyncOnStaticMethod(); |
100 | } |
101 | }).start(); |
102 | } |
103 |
104 | public static void main(String[] args) { |
105 | case1(); |
106 | case2(); |
107 | } |
108 | } |
从上面的代码我们可以看出synchronized加在方法上本质上还是等价于加在对象上的。
如果synchronized加在一个类的普通方法上,那么相当于synchronized(this)。
如果synchronized加载一个类的静态方法上,那么相当于synchronized(Class对象)。
在使用多线程的时候,知道这个是很关键的,因为synchronized的两种不用用法可能导致两段不相干的代码是互斥的,增加了同步的开销(例如这里的函数testSyncOnThis和testSyncOnMethod,他们在同一个对象this上加了锁),更严重的是可能导致死锁。
注:如果要试验,上面的case1和case2请分开运行(可以跑两次,每次注释掉其中一个语句),这样子可以看得比较清楚。
转自 http://blog.iamzsx.me/show.html?id=126001