android開発のsynchronizedの使い方
9910 ワード
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>:同期を実現するには、大きなシステムオーバーヘッドを代価として必要とし、デッドロックをもたらすこともあるので、無駄な同期制御をできるだけ避ける.