android開発のsynchronizedの使い方

9910 ワード

  • 概要synchronizedはJavaのキーワードであり、同期ロックです.クラスの作用の範囲はsynchronizedの後ろの括弧で囲まれた部分の作用の対象は:このクラスの中のすべてのオブジェクト1.2>:静的方法の作用の範囲は:全体の静的方法の作用の対象は:このクラスの中のすべての対象1.3>:コードブロック:修飾されたコードブロックが同期コードブロックの作用と呼ばれる範囲は:括弧で囲まれた部分的な役割のオブジェクトは、このコードブロックを呼び出すオブジェクト1.4>:メソッド:修飾されたメソッドを同期メソッドと呼ぶ役割の範囲は、メソッド全体の役割のオブジェクトは、このメソッドを呼び出すオブジェクト
  • である.
  • 例解析2.1>:synchronized修飾コードブロック
  • public class MainActivity extends AppCompatActivity {
    
        private static final String TAG = "MainActivity" ;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            SyncThread syncThread = new SyncThread() ;
            Thread thread1 = new Thread(syncThread , "SyncThread1") ;
            Thread thread2 = new Thread(syncThread , "SyncThread2") ;
            thread1.start();
            thread2.start();
        }
    
        class SyncThread implements Runnable{
            private int count ;
            public SyncThread(){
                count = 0 ;
            }
    
            @Override
            public void run() {
                synchronized (this){
                    for (int i = 0; i < 5; i++) {
                        try {
                            Log.d("mainActivity-->", Thread.currentThread().getName() + ":" + (count++)) ;
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
            public int getCount(){
                return count ;
            }
        }
    }
    

    上の運転結果は
    //SyncThread2:0
    //SyncThread2:1
    //SyncThread2:2
    //SyncThread2:3
    //SyncThread2:4
    //SyncThread1:5
    //SyncThread1:6
    //SyncThread1:7
    //SyncThread1:8
    //SyncThread1:9
    

    以上から分かるように、2つのスレッドthread 1とthread 2が「同じsyncThreadオブジェクト」のsynchronizedコードブロックにアクセスすると、同じ時点で1つの実行スレッドしか実行できず、もう1つがブロックを実行するのを待つ必要があり、thread 1はsynchronizedコードブロックを実行するときに現在のオブジェクトをロックし、オブジェクトロックは、コードブロックの実行後にのみ解放され、次のスレッドがオブジェクトを実行およびロックできます.
    私たちは今
    Thread thread1 = new Thread(syncThread , "SyncThread1") ;
    Thread thread2 = new Thread(syncThread , "SyncThread2") ;
    

    この2つの文は
    Thread thread1 = new Thread(new SyncThread() , "SyncThread1") ;
    Thread thread2 = new Thread(new SyncThread() , "SyncThread2") ;
    

    実行結果は
    //SyncThread1:0
    //SyncThread2:0
    //SyncThread1:1
    //SyncThread2:1
    //SyncThread1:2
    //SyncThread2:2
    //SyncThread1:3
    //SyncThread2:3
    //SyncThread1:4
    //SyncThread2:4
    

    現象:thread 1とthread 2は同時に原因:synchronizedがコードブロックを修飾する時、コードブロックの中のオブジェクトだけをロックして、1つのオブジェクトは1つのロック[lock]だけがそれに関連して、上のコードは同等です
    SyncThread syncThread1 = new SyncThread();
    SyncThread syncThread2 = new SyncThread();
    Thread thread1 = new Thread(syncThread1, "SyncThread1");
    Thread thread2 = new Thread(syncThread2, "SyncThread2");
    thread1.start();
    thread2.start();
    

    このときsyncThread 1は何syncThread 2、スレッドthread 1はsyncThread 1オブジェクトに対応するsynchronizedのコードを実行し、スレッドthread 2はsyncThread 2に対応するsynchronizedオブジェクトを実行し、synchronizedがロックされているのはオブジェクトであることを知っています.このときsynchronizedはsyncThread 1オブジェクトとsyncThread 2オブジェクトをそれぞれロックします.この2つのロックは互いに干渉しているので、2つのスレッドは同時に実行できます.
    コード:https://github.com/shuai999/ThreadDemo
    2.2:1つのスレッドが1つのオブジェクトのsynchronized(this)コードブロックにアクセスする場合、他のスレッドもそのオブジェクトの非synchronized(this)コードブロックにアクセスでき、ブロックされた複数のスレッドが同じオブジェクトのsynchronized(this)コードブロックと非synchronized(this)コードブロックにアクセスできます.例は次のとおりです.
    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            
            Counter counter = new Counter() ;
            //   :Runnable        :   
            Thread thread1 = new Thread(counter , "A") ;
            Thread thread2 = new Thread(counter , "B") ;
            thread1.start();
            thread2.start();
            
        }
    
        class Counter implements Runnable{
    
            private int count ;
            public Counter(){
                count = 0 ;
            }
    
            public void countAdd(){
                //synchronized   
                synchronized (this){
                    for (int i = 0; i < 5; i++) {
                        try {
                            Log.d("threadName--->" , Thread.currentThread().getName() +":" + (count++)) ;
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
    
    
            // synchronized   ,  count      ,      synchronized
            public void printAdd(){
                for (int i = 0; i < 5; i++) {
                    try {
                        Log.d("threadName--->" , Thread.currentThread().getName() + "count:" + count) ;
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
    
    
            @Override
            public void run() {
                String threadName = Thread.currentThread().getName() ;
                if (threadName.equals("A")){
                    countAdd();
                }else if (threadName.equals("B")){
                    printAdd();
                }
            }
        }
    
    //    Bcount:0
    //    A:0
    //    Bcount:1
    //    A:1
    //    Bcount:2
    //    A:2
    //    Bcount:3
    //    A:3
    //    Bcount:4
    //    A:4
        /*         */
        /*      ,countAdd()   synchronized   ,printAdd()  synchronized   。
                       synchronized    ,              synchronized        */
    }
    

    具体的なコードはgithubにアップロードされました:https://github.com/shuai999/ThreadDemo3
    2.3:オブジェクトへのロックコードを次のように指定します.
    /**
     * @author : Created by ces
     * @date: on 2018/1/28.
     * @function:          
     */
    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            Account account = new Account("zhangsan" , 10000.0f) ;
            AccountOperator operator = new AccountOperator(account) ;
    
            final int THREAD_NUM = 5 ;
            Thread threads[] = new Thread[THREAD_NUM] ;
            for (int i = 0; i < THREAD_NUM; i++) {
                threads[i] = new Thread(operator , "Thread" + i);
                threads[i].start();
            }
        }
    
        public class AccountOperator implements Runnable{
    
            private Account account ;
            public AccountOperator(Account account){
                this.account = account ;
            }
    
            @Override
            public void run() {
                synchronized (account){
                    //  500
                    account.deposit(500);
                    //  500
                    account.withDraw(500);
                    Log.e("cesAccount--->", Thread.currentThread().getName() + ":" + account.getBalance()) ;
                    //      
    //                Thread0:10000.0
    //                Thread1:10000.0
    //                Thread2:10000.0
    //                Thread3:10000.0
    //                Thread4:10000.0
                }
            }
        }
    }
    
    /**
     * @author : Created by ces
     * @date: on 2018/1/28.
     * @function:          
     */
    public class Account {
        String name ;
        float amount ;
    
        public Account(String name , float amount){
            this.name = name ;
            this.amount = amount ;
        }
    
        //  
        public void deposit(float amt){
            amount +=amt;
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
        }
    
        //  
        public void withDraw(float amt){
            amount -=amt ;
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
        public float getBalance(){
            return  amount ;
        }
    
    }
    

    AccountOperatorクラスでは、accountオブジェクトにロックを追加します.この場合、1つのスレッドがaccountオブジェクトにアクセスすると、他のスレッドがブロックされ、そのスレッドがaccountオブジェクトにアクセスして終了するまで、つまり誰がそのロックを手に入れると、その制御されたコードを実行することができます.具体的なコードはgithubにアップロードされましたhttps://github.com/shuai999/ThreadDemo4.git
    2.4 1つの方法を修飾する
      :public synchronized void method(){//todo};
    

    synchronized修飾方法はコードブロックと似ていますが、作用範囲が違います.修飾されたコードブロックは括弧で囲まれた範囲です.修飾の方法は関数全体です.
    synchronizedで修飾する方法では、以下の点に注意してください.synchronizedキーワードは1.1を継承できません:親クラスのメソッドでsynchronizedを使用し、子クラスでこのメソッドを上書きした場合、子クラスでこのメソッドのデフォルトは同期ではありません.メソッドにsynchronizedを明示的に追加する必要があります.1.2:子メソッドで親メソッドを呼び出すこともできます.これにより、子メソッドは同期ではありませんが、子メソッドは親メソッドを呼び出すので、子メソッドは同期に相当します.この2つのメソッドコードは次のとおりです.
             synchronized:
        class Parent{
            public synchronized void method(){}
        }
       class Child extends Parent{
            public synchronized void method(){}
        }
                   :
        class Parent{
            public synchronized void method(){}
        }
        class Childe extends Parent{
            public void method(){
                super.method() ;
            }
        }
    

    注:1>:インタフェースメソッドを定義するときにsynchronizedを使用できません2>:構築メソッドではsynchronizedは使用できませんが、synchronizedコードブロックを使用して同期できます.
    2.5:静的メソッドを修飾し、コードは以下の通りです.
    public synchronized static void method() {
       // todo
    }
    

    2.6:クラスを修飾します.コードは次のとおりです.
    class ClassName {
       public void method() {
          synchronized(ClassName.class) {
             // todo
          }
       }
    }
    

    まとめ:1>:synchronizedがメソッドに追加されてもオブジェクトに追加されても、その作用するオブジェクトが非静的である場合、その取得したロックはオブジェクトです.synchronizedが静的メソッドまたはクラスに作用する場合、取得されたオブジェクトはクラスであり、クラスのすべてのオブジェクトは同じロックである.2>:各オブジェクトにはロックが1つしかありません.このロックを手に入れると、制御されているコードを実行することができます.3>:同期を実現するには、大きなシステムオーバーヘッドを代価として必要とし、デッドロックをもたらすこともあるので、無駄な同期制御をできるだけ避ける.