synchronized有两种,一种是锁定方法,一种是锁定代码块,区别仅是锁定代码块更加灵活,性能消耗更少。
下面举两个例子,第一个:
public class TestSynchronizedMethod1 implements Runnable{ /** * 当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。 * 另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。 * @author cdzhujun */ public void run(){ synchronized (this) { for(int i=0;i<5;i++){ System.out.println(Thread.currentThread().getName() + " synchronized loop " + i); } } } public static void main(String[] args) { TestSynchronizedMethod1 t1 = new TestSynchronizedMethod1(); Thread ta = new Thread(t1,"A"); Thread tb = new Thread(t1,"B"); ta.start(); tb.start(); } }
执行结果为:
A synchronized loop 0 A synchronized loop 1 A synchronized loop 2 A synchronized loop 3 A synchronized loop 4 B synchronized loop 0 B synchronized loop 1 B synchronized loop 2 B synchronized loop 3 B synchronized loop 4
以上程序演示了锁的基本作用。
第二个例子:
public class TestSynchronizedMethod2 implements Runnable { /** * 然而,当一个线程访问object的一个synchronized(this)同步代码块时, * 另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。 * @author cdzhujun */ int b = 100; public synchronized void m1() throws Exception { b = 1000; Thread.sleep(5000); System.out.println("b = " + b); } //m2方法可以被主线程调用,变量b作为一个资源仍然可以被访问,synchronized仅锁住的是m1这个方法,并没有锁住b这个变量资源 public void m2() throws Exception { Thread.sleep(2500); b = 2000; } // public void m2() { // System.out.println(b); // } public void run() { try { m1(); } catch (Exception e) { e.printStackTrace(); } } public static void main(String[] args) throws Exception { TestSynchronizedMethod2 tsm = new TestSynchronizedMethod2(); Thread t = new Thread(tsm); t.start(); Thread.sleep(1000); tsm.m2(); } }
程序执行结果为:5秒后,输出:b = 2000
第二个例子的解释:main这个主线程调用tsm.m2()这个方法,因m2()是非synchronized方法,故可以访问。所以程序的执行顺序是,tsm启动了一个新线程,等待的5秒过程中,主线程main调用tsm.m2()这个方法,将b设置为2000,然后5秒后m1再输出,此时b已经为2000。(m1里确实设置了b=1000,但2500毫秒后,m2这个方法又重新设置了值)。
这里注意:synchronized锁住的是当前这个对象的所有加锁的方法块和这个对象。
如何理解?就是说:
1、当一个线程访问object的一个synchronized(this)同步代码块时, 另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。
2、不同的对象实例的 synchronized方法是不相干扰的。也就是说,其它线程照样可以同时访问相同类的另一个对象实例中的synchronized方法。
3、其他线程访问该object对象的非synchronized代码块时,对象的成员变量,作为一种资源,仍然可以被访问(第二个例子中的变量b)。
通过以上例子,相信大家对synchronized关键字的理解应该会有一个正确的认识。