Javaのsynchronizedの詳細について

8024 ワード

初めてここで開博したことを記念して~ほほほ~
Javaにおけるsynchronized(同期呼び出し)については,これまであまり理解されていなかったが,ここで詳細な研究を行う.
第一篇:
Java言語のキーワードは、メソッドまたはコードブロックを修飾するために使用される場合、同じ時点で最大1つのスレッドだけがセグメントコードを実行することを保証します.
     一、2つの同時スレッドが同じオブジェクトobjectのsynchronized(this)同期コードブロックにアクセスすると、1時間に1つのスレッドしか実行できない.別のスレッドは、現在のスレッドがこのコードブロックを実行するまで待たなければなりません.
     二、しかしながら、あるスレッドがobjectのsynchronized(this)同期コードブロックにアクセスする場合、別のスレッドは、object内の非synchronized(this)同期コードブロックにアクセスすることができる.
     三、特に重要なのは、1つのスレッドがobjectのsynchronized(this)同期コードブロックにアクセスすると、他のスレッドがobject内の他のすべてのsynchronized(this)同期コードブロックへのアクセスがブロックされることである.
     四、第三の例は、他の同期コードブロックにも同様に適用される.すなわち、objectのsynchronized(this)同期コードブロックにスレッドがアクセスすると、このobjectのオブジェクトロックが得られる.その結果、objectオブジェクトのすべての同期コード部分への他のスレッドのアクセスが一時的にブロックされる.
     五、以上の規則は他の対象ロックに対しても同様に適用する.
例:       一、2つの同時スレッドが同じオブジェクトobjectのsynchronized(this)同期コードブロックにアクセスすると、1時間に1つのスレッドしか実行できない.別のスレッドは、現在のスレッドがこのコードブロックを実行するまで待たなければなりません.
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(); 
          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)同期コードブロックにアクセスすることができる.
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(); 
          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
     三、特に重要なのは、1つのスレッドがobjectのsynchronized(this)同期コードブロックにアクセスすると、他のスレッドがobject内の他のすべてのsynchronized(this)同期コードブロックへのアクセスがブロックされることである.
     //  Thread2.m4t2()  : 
     public void 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()    :

     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
     五、以上の規則は他のオブジェクトロックにも適用される.
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();
  }
}

 
結果:
スレッドt 1はInnerに対するオブジェクトロックを取得するが、スレッドt 2は同じInnerの非同期部分にアクセスするためである.したがって、2つのスレッドは互いに干渉しません.
     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) { 
               } 
          } 
     }

 
結果:
スレッドt 1とt 2は、同じInnerオブジェクトのうちの2つの関係のない部分にアクセスしているが、t 1が先にInnerに対するオブジェクトロックを取得しているため、m 4 t 2()がInnerの同期方法であるため、t 2のInner.m 4 t 2()へのアクセスもブロックされる.
     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