JAva同期ロック(synchronized)


JAvaのcpuが各スレッドに分けたタイムスライスはランダムで、javaの多くは複数のスレッドが1つのリソースを共有しています.例えば、汽車が切符を売っているので、汽車の切符は一定ですが、汽車の切符を売る窓口はあちこちにあり、各ウィンドウは1つのスレッドに相当し、このような多くのスレッドはすべての汽車の切符というリソースを共有しています.1つの時点で2つのスレッドが同時にこのリソースを使用すると、彼らが取り出した汽車の切符は同じ(座席番号は同じ)ので、乗客に迷惑をかけます.たとえば、次のような手順があります.
package com.dr.runnable2;class TicketSouce implements Runnable{//チケットの総数private int ticket=10;public void run(){for(int i=1;i<50;i+){if(ticket>0){//休眠1秒で効果をより顕著にするためにtry{Thread.sleep(1000);}catch(InterruptedException){e.printStackTrace();}System.out.println(Thread.currentThread(Thread.currentThread)());}catch(InterruptedException){e.printStackTrace();}System.out.println(Thread..getName()+「番窓口売り」+this.ticket-+"チケット";}}}}public class Test{public static void main(String args[]){TicketSouce mt=new TicketSouce();//列車チケットに基づいて3つのウィンドウnew Thread(mt,"a").start();new Thread(mt,"b").start();new Thread(mt,"c").start();
}
プログラムの実行結果は次のとおりです.
ticket
a番とc番の窓口で7番の切符が売られ、a番とc番の窓口でそれぞれ0番と-1番の切符が売られているのが見えます.このような原因は、1、aスレッドとbスレッドがticket=7のとき、aスレッドが7番の切符を取り出した後、ticketがまだ来ていないことと1 bのスレッドを減らしてticketを取り出したことである.このときticketは7に等しい.2、ticket=1の時、bスレッドは1番の切符を取り出して、ticketはまだ来ていないと1を減らして、a、cスレッドは前後してif判断文に入って、この時ticketは1を減らして、それではa、cスレッドが切符を取る時0番と-1番の切符を取りました.
このような状況がどのように変わったのか、私たちはこのようにすることができます:1つのスレッドが汽車の切符という資源を使うとき、私たちはそれに鍵を渡して、それが仕事を終えた後に別のこの資源を使うスレッドに鍵をかけます.これにより、上記のような状況は発生しません.このロックを実現する機能にはsynchronizedというキーワードが必要です.
synchronizedというキーワードには2つの使い方1、置き方名形成同期方法があります.2.ブロックの前に置いて同期ブロックを構成する.
1、同期方法を用いて上記の例を以下のようにする.
package com.dr.runnable2;class TicketSouce implements Runnable{//票の総数private int ticket=10;public void run(){for(int i=1;i<50;i+){try{////休眠1秒で効果をより顕著にするために効果が出ない可能性があるThread.sleep(1000);}catch(InterruptedException){e.printStackTrace();}this.sale();}}public synchronized void sale(){if(ticketttSouce){if>0){System.out.println(Thread.currentThread().getName()+「番窓口売り」+this.ticket--+「番票」);}}}}}}public class Test{public static void main(String args[]){TicketSouce mt=new TicketSouce();//////列車切符に基づいて3つの窓口new Thread(mt,"a").start();new Thread(mt,"b").start();new Thread(mt,"c")).start();new Thread(mt,"c"))..start();}
}
プログラムの出力結果は次のとおりです.
ticket1
2、同期ブロックを使用して上記の例を修正する:
package age com.dr.runnable 2;class TicketSouce implements Runnable{////チケットの総数private int ticket=10;public void run(){for(int i=1;i<50;i+){synchronized(this){if(ticket>0){//休眠1 s秒で、効果をより顕著にするためにtry{Thread.sleep(1000);}catch(InterruptedException e){e.printStackTrace(1000);;}catch(InterruptedException){e.printStackTrace((){e){e.printStackTrace((()){e);}System.out.println(Thread.currentThread().getName()+「番窓口売り」+this.ticket--+「番票」;}}}}}}}}}}}}}}}}}}}}}}}}.public static void main(String args[]){TicketSouce mt=new TicketSouce();//////列車切符に基づいて3つの窓口new Thread(mt,"a").start();new Thread(mt,"b").start();new Thread(mt,"c").start();new Thread(mt,"c").").start();}
}
プログラムの出力結果:
ticket2
上記の状況は正しいです.デバッグ中にsynchronizedを位置を間違えてエラーを起こした結果、エラーの原因を見てみましょう.
プログラム1:
package age com.dr.runnable 2;class TicketSouce implements Runnable{///チケットの総数private int ticket=10;public void run(){for(int i=1;i<50;i+){if(ticket>0)synchronized(this){//1秒休止中、効果をより明らかにするためにtry{Thread.sleep(1000);}catch(InterruptedException e){e.printStackTrace();;;}System.out.println(Thread.currentThread().getName()+「番窓口売り」+this.ticket--+「番票」;}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}).start();}
}
プログラム1の実行結果:
ticket3
プログラム1の出力結果はなんと0番と-1番の切符が出た.原因はsynchronizedが位置を間違えたためであり、プログラム1はsynchronizedをif文の後ろに置いた.bスレッドが2好票を取り出した後、ticket=1となり、次のa、b、cスレッドが来るとticket=1>0がif文体に入り、このときcpuがスレッドに分けたタイムスライスはbがc後aであるという結果になった果物.
プログラム2:
package age com.dr.runnable 2;class TicketSouce implements Runnable{///チケットの総数private int ticket=10;public void run(){synchronized(this){for(int i=1;i<50;i+){if(ticket>0){///休眠1 s秒では、効果をより顕著にするためにtry{Thread.sleep(1000);}catch(InterruptedException e){e.printStackTrace(1000);{e.printStackTrace)(){e){e.package com.com.com.com.com.ruckage com.com.;}System.out.println(Thread.currentThread().getName()+「番窓口売り」+this.ticket-+「番票」}}
                       }
        }

}public class Test{public static void main(String args[]){TicketSouce mt=new TicketSouce();//汽車の切符に基づいて3つのウィンドウnew Thread(mt,“a”).start();new Thread(mt,“b”).start();new Thread(mt,“c”).start();
}
プログラム2の出力結果:
ticket4
プログラム2の出力結果は間違いなく0番と-1番の切符を出力していないように見えますが、複数の窓口で切符を販売する機能を実現していません.鍵を位置を間違えたため、1つの窓口しか切符を販売していません.cpuがタイムシートをスレッドに分けると、この窓口はすべての切符を売り切れなければなりません.