Java synchronized详解1

Java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码。
     一、当两个并发线程访问 同一个对象 object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。
     二、然而,当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以 访问该object中的 非synchronized(this) 同步代码块
     三、尤其关键的是,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对 object中所有其它 synchronized(this) 同步代码块的访问将被阻塞
     四、第三个例子同样适用其它同步代码块。也就是说,当一个线程访问object的一个synchronized(this)同步代码块时,它就获得了这个object的对象锁。结果,其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。
     五、以上规则对其它对象锁同样适用.

举例说明:  
一、当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。
package ths;

public class Thread1 implements Runnable {  
    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) {  
          Thread1 t1 = new Thread1();   A线程和B线程同时访问t1对象,但是有同步锁,B将会被阻塞
         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

二、然而,当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。
package ths;

public class Thread2 {  
    public void m4t1() {  
         synchronized(this) {  
              int i = 5;  
              while( i-- > 0) {  
                   System.out.println(Thread.currentThread().getName() + " : " + i);  
                   try {  
                        Thread.sleep(500);  
                   } catch (InterruptedException ie) {  
                   }  
              }  
         }  
    }  
    public void m4t2() {  
         int i = 5;  
         while( i-- > 0) {  
              System.out.println(Thread.currentThread().getName() + " : " + i);  
              try {  
                   Thread.sleep(500);  
              } catch (InterruptedException ie) {  
              }  
         }  
    }  
    public static void main(String[] args) {  
         final Thread2 myt2 = new Thread2();   //线程t1和t2同时访问myt2,但是线程t2访问的是非同步方法,所以不会被阻塞
         Thread t1 = new Thread(  new Runnable() {  public void run() {  myt2.m4t1();  }  }, "t1"  );  
          Thread t2 = new Thread(  new Runnable() {  public void run() { myt2.m4t2();   }  }, "t2"  );  
          t1.start();  
         t2.start();  
    } 
}

结果:  
     t1 : 4  
     t2 : 4  
     t1 : 3  
     t2 : 3  
     t1 : 2  
     t2 : 2  
     t1 : 1  
     t2 : 1  
     t1 : 0  
     t2 : 0

三、尤其关键的是,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。
//修改Thread2.m4t2()方法:  
    public void m4t2() {  
//m4t2的方法写成同步块,当两个线程分别访问两个方法时,必定有一个也会被阻塞
         synchronized(this) {  
              int i = 5;  
              while( i-- > 0) {  
                   System.out.println(Thread.currentThread().getName() + " : " + i);  
                   try {  
                        Thread.sleep(500);  
                   } catch (InterruptedException ie) {  
                   }  
              }  
         }

    }

结果:
     t1 : 4  
     t1 : 3  
     t1 : 2  
     t1 : 1  
     t1 : 0  
     t2 : 4  
     t2 : 3  
     t2 : 2  
     t2 : 1  
     t2 : 0

四、第三个例子同样适用其它同步代码块。也就是说,当一个线程访问object的一个synchronized(this)同步代码块时,它就获得了这个object的对象锁。结果,其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。
//修改Thread2.m4t2()方法如下:
//m4t2方法改为同步方法,t1线程和t2线程同时访问两个方法时,t2线程会被阻塞
    public synchronized void m4t2() {  
         int i = 5;  
         while( i-- > 0) {  
              System.out.println(Thread.currentThread().getName() + " : " + i);  
              try {  
                   Thread.sleep(500);  
              } catch (InterruptedException ie) {  
              }  
         }  
    }

结果:  
     t1 : 4  
     t1 : 3  
     t1 : 2  
     t1 : 1  
     t1 : 0  
     t2 : 4  
     t2 : 3  
     t2 : 2  
     t2 : 1  
     t2 : 0

五、以上规则对其它对象锁同样适用:
package ths;

public class Thread3 { 
    class Inner { 
         private void m4t1() { 
              int i = 5; 
              while(i-- > 0) { 
                   System.out.println(Thread.currentThread().getName() + " : Inner.m4t1()=" + i); 
                    try { 
                        Thread.sleep(500); 
                   } catch(InterruptedException ie) { 
                   } 
              } 
         } 
         private void m4t2() { 
              int i = 5; 
              while(i-- > 0) { 
                   System.out.println(Thread.currentThread().getName() + " : Inner.m4t2()=" + i); 
                    try { 
                        Thread.sleep(500); 
                   } catch(InterruptedException ie) { 
                   } 
              } 
         } 
    } 
    private void m4t1(Inner inner) { 
         synchronized(inner) {  //使用对象锁 
         inner.m4t1(); 
    } 
    private void m4t2(Inner inner) { 
         inner.m4t2(); 
    } 
    public static void main(String[] args) { 
         final Thread3 myt3 = new Thread3(); 
         final Inner inner = myt3.new Inner(); 
//因为两个方法都使用了对象锁,而且此对象的内部方法都不是同步的,所以只要线程访问的不是同一方法,将不会被阻塞
         Thread t1 = new Thread( new Runnable() {public void run() { myt3.m4t1(inner);} }, "t1"); 
     Thread t2 = new Thread( new Runnable() {public void run() { myt3.m4t2(inner);} }, "t2"); 
    t1.start(); 
    t2.start(); 
 } 
}

结果:
尽管线程t1获得了对Inner的对象锁,但由于线程t2访问的是同一个Inner中的非同步部分。所以两个线程互不干扰。
     t1 : Inner.m4t1()=4  
     t2 : Inner.m4t2()=4  
     t1 : Inner.m4t1()=3  
     t2 : Inner.m4t2()=3  
     t1 : Inner.m4t1()=2  
     t2 : Inner.m4t2()=2  
     t1 : Inner.m4t1()=1  
     t2 : Inner.m4t2()=1  
     t1 : Inner.m4t1()=0  
     t2 : Inner.m4t2()=0

现在在Inner.m4t2()前面加上synchronized:
private synchronized void m4t2() {  
    int i = 5;  
    while(i-- > 0) {  
         System.out.println(Thread.currentThread().getName() + " : Inner.m4t2()=" + i);  
         try {  
              Thread.sleep(500);  
         } catch(InterruptedException ie) {  
         }  
    }  
}

结果:
尽管线程t1与t2访问了同一个Inner对象中两个毫不相关的部分,但因为t1先获得了对Inner的对象锁,所以t2对Inner.m4t2()的访问也被阻塞,因为m4t2()是Inner中的一个同步方法。
     t1 : Inner.m4t1()=4  
     t1 : Inner.m4t1()=3  
     t1 : Inner.m4t1()=2  
     t1 : Inner.m4t1()=1  
     t1 : Inner.m4t1()=0  
     t2 : Inner.m4t2()=4  
     t2 : Inner.m4t2()=3  
     t2 : Inner.m4t2()=2  
     t2 : Inner.m4t2()=1  
     t2 : Inner.m4t2()=0

猜你喜欢

转载自blog.csdn.net/howinfun/article/details/79374559
今日推荐