例を使用して、同期ブロックに対する同期メソッドの利点を教えてもらえますか?
例を使用して、同期ブロックに対する同期メソッドの利点を教えてもらえますか?
回答:
例を使用して、同期ブロックに対する同期メソッドの利点を誰かに教えてもらえますか?ありがとう。
ブロックに対して同期メソッドを使用する明確な利点はありません。
おそらく唯一のもの(しかし、私はそれを利点とは言わないでしょう)は、オブジェクト参照を含める必要がないことです this
。
方法:
public synchronized void method() { // blocks "this" from here....
...
...
...
} // to here
ブロック:
public void method() {
synchronized( this ) { // blocks "this" from here ....
....
....
....
} // to here...
}
見る?まったく利点はありません。
ただし、ブロックにはメソッドよりも利点があります。メソッドを同期するとオブジェクト全体がロックされますが、別のオブジェクトをロックとして使用できるため、ほとんどの場合、柔軟性に優れています。
比較:
// locks the whole object
...
private synchronized void someInputRelatedWork() {
...
}
private synchronized void someOutputRelatedWork() {
...
}
対
// Using specific locks
Object inputLock = new Object();
Object outputLock = new Object();
private void someInputRelatedWork() {
synchronized(inputLock) {
...
}
}
private void someOutputRelatedWork() {
synchronized(outputLock) {
...
}
}
また、メソッドが大きくなった場合でも、同期されたセクションを分離しておくことができます。
private void method() {
... code here
... code here
... code here
synchronized( lock ) {
... very few lines of code here
}
... code here
... code here
... code here
... code here
}
synchronized
ブロックは、2つの命令を使用して実装され、monitorenter
且つmonitorexit
、プラスそれを確実に例外ハンドラがmonitorexit
あっても例外的な場合に呼び出されます。synchronized
メソッドを使用すると、すべて保存されます。
唯一の真の違いは、同期されたブロックが、同期するオブジェクトを選択できることです。同期メソッドは'this'
、(または同期クラスメソッドの対応するClassインスタンス)のみを使用できます。たとえば、これらは意味的に同等です。
synchronized void foo() {
...
}
void foo() {
synchronized (this) {
...
}
}
後者は、任意のオブジェクト(多くの場合、メンバー変数)の関連ロックを競合できるため、より柔軟です。また、ブロックの前後で同時にコードを実行することもできますが、それでもメソッド内で実行できるため、より詳細です。もちろん、並行コードを個別の非同期メソッドにリファクタリングすることで、同期メソッドを簡単に使用することもできます。コードをよりわかりやすくする方を使用します。
長所:
短所:
長所:
短所:
個人的には、同期が必要なものにのみ焦点を当てたクラスで同期メソッドを使用することを好みます。このようなクラスは可能な限り小さくする必要があるため、同期を簡単に確認できます。他のものは同期を気にする必要はありません。
主な違いは、同期ブロックを使用すると、これ以外のオブジェクトをロックする可能性があり、これにより柔軟性が大幅に向上します。
メッセージキューと、複数のメッセージプロデューサーとコンシューマーがあるとします。プロデューサーが互いに干渉することは望ましくありませんが、コンシューマーはプロデューサーを待たずにメッセージを取得できる必要があります。したがって、オブジェクトを作成するだけです
Object writeLock = new Object();
そして、これからプロデューサーが新しいメッセージを追加したいときはいつでも、それをロックします。
synchronized(writeLock){
// do something
}
そのため、コンシューマーは引き続き読み取り、プロデューサーはロックされます。
同期方法
同期メソッドには2つの効果があります。
まず、1つのスレッドがオブジェクトの同期メソッドを実行しているとき、同じオブジェクトの同期メソッドを呼び出す他のすべてのスレッドは、最初のスレッドがオブジェクトで完了するまでブロックします(実行を中断します)。
第2に、同期メソッドが終了すると、同じオブジェクトの同期メソッドの以降の呼び出しと、前に発生する関係が自動的に確立されます。これにより、オブジェクトの状態の変更がすべてのスレッドから見えるようになります。
コンストラクターは同期できないことに注意してください—コンストラクターでsynchronizedキーワードを使用すると、構文エラーになります。コンストラクターの同期は意味をなさない。オブジェクトを作成するスレッドのみが、オブジェクトの構築中にアクセスできるようにする必要があるためです。
同期ステートメント
同期されたメソッドとは異なり、同期されたステートメントは、固有のロックを提供するオブジェクトを指定する必要があります。ほとんどの場合、これを使用してリストまたはマップへのアクセスを同期しますが、オブジェクトのすべてのメソッドへのアクセスをブロックしたくありません。
Q:組み込みロックと同期同期は、組み込みロックまたはモニターロックと呼ばれる内部エンティティを中心に構築されます。(API仕様では、多くの場合、このエンティティを単に「モニター」と呼びます。)固有のロックは、同期の両方の側面で役割を果たします。オブジェクトの状態への排他的アクセスを強制し、可視性に不可欠な発生前の関係を確立します。
すべてのオブジェクトには、固有のロックが関連付けられています。慣例により、オブジェクトのフィールドへの排他的で一貫性のあるアクセスを必要とするスレッドは、オブジェクトにアクセスする前にオブジェクトの固有ロックを取得し、それらが完了したら固有ロックを解放する必要があります。スレッドは、ロックを取得してからロックを解放するまでの間に、固有のロックを所有していると言います。スレッドが固有のロックを所有している限り、他のスレッドは同じロックを取得できません。他のスレッドは、ロックを取得しようとするとブロックされます。
package test;
public class SynchTest implements Runnable {
private int c = 0;
public static void main(String[] args) {
new SynchTest().test();
}
public void test() {
// Create the object with the run() method
Runnable runnable = new SynchTest();
Runnable runnable2 = new SynchTest();
// Create the thread supplying it with the runnable object
Thread thread = new Thread(runnable,"thread-1");
Thread thread2 = new Thread(runnable,"thread-2");
// Here the key point is passing same object, if you pass runnable2 for thread2,
// then its not applicable for synchronization test and that wont give expected
// output Synchronization method means "it is not possible for two invocations
// of synchronized methods on the same object to interleave"
// Start the thread
thread.start();
thread2.start();
}
public synchronized void increment() {
System.out.println("Begin thread " + Thread.currentThread().getName());
System.out.println(this.hashCode() + "Value of C = " + c);
// If we uncomment this for synchronized block, then the result would be different
// synchronized(this) {
for (int i = 0; i < 9999999; i++) {
c += i;
}
// }
System.out.println("End thread " + Thread.currentThread().getName());
}
// public synchronized void decrement() {
// System.out.println("Decrement " + Thread.currentThread().getName());
// }
public int value() {
return c;
}
@Override
public void run() {
this.increment();
}
}
同期されたメソッド、ブロック、同期なしのさまざまな出力をクロスチェックします。
Javaコンパイラーがソースコードをバイトコードに変換する場合、同期されたメソッドと同期されたブロックの処理は大きく異なります。
JVMが同期されたメソッドを実行すると、実行中のスレッドは、メソッドのmethod_info構造にACC_SYNCHRONIZEDフラグが設定されていることを識別し、オブジェクトのロックを自動的に取得してメソッドを呼び出し、ロックを解放します。例外が発生すると、スレッドは自動的にロックを解放します。
一方、メソッドブロックを同期すると、オブジェクトのロックと例外処理を取得するためのJVMの組み込みサポートがバイパスされ、機能をバイトコードで明示的に記述する必要があります。同期されたブロックを持つメソッドのバイトコードを読み取る場合、この機能を管理するための追加の操作が数十以上表示されます。
これは、同期メソッドと同期ブロックの両方を生成する呼び出しを示しています。
public class SynchronizationExample {
private int i;
public synchronized int synchronizedMethodGet() {
return i;
}
public int synchronizedBlockGet() {
synchronized( this ) {
return i;
}
}
}
このsynchronizedMethodGet()
メソッドは、次のバイトコードを生成します。
0: aload_0
1: getfield
2: nop
3: iconst_m1
4: ireturn
そして、ここにsynchronizedBlockGet()
メソッドからのバイトコードがあります:
0: aload_0
1: dup
2: astore_1
3: monitorenter
4: aload_0
5: getfield
6: nop
7: iconst_m1
8: aload_1
9: monitorexit
10: ireturn
11: astore_2
12: aload_1
13: monitorexit
14: aload_2
15: athrow
同期化されたメソッドとブロックの1つの重要な違いは、同期化されたブロックは一般にロックの範囲を縮小することです。ロックの範囲はパフォーマンスに反比例するため、コードの重要なセクションのみをロックすることを常にお勧めします。同期ブロックを使用する最良の例の1つは、全体をロックする代わりにシングルトンパターンでダブルチェックロックを行うことです。getInstance()
メソッドシングルトンインスタンスの作成に使用されるコードのクリティカルセクションのみをロックします。ロックが必要なのは1〜2回だけなので、これによりパフォーマンスが大幅に向上します。
同期メソッドを使用する場合、静的同期メソッドと非静的同期メソッドの両方を混在させる場合は、さらに注意が必要です。
monitorenter
とmonitorexit
、コードを実行する前に。
ほとんどの場合、これを使用してリストまたはマップへのアクセスを同期しますが、オブジェクトのすべてのメソッドへのアクセスをブロックしたくありません。
次のコードでは、リストを変更する1つのスレッドは、マップを変更するスレッドの待機をブロックしません。メソッドがオブジェクトで同期されている場合、各メソッドは、行っている変更が競合しない場合でも待機する必要があります。
private List<Foo> myList = new ArrayList<Foo>();
private Map<String,Bar) myMap = new HashMap<String,Bar>();
public void put( String s, Bar b ) {
synchronized( myMap ) {
myMap.put( s,b );
// then some thing that may take a while like a database access or RPC or notifying listeners
}
}
public void hasKey( String s, ) {
synchronized( myMap ) {
myMap.hasKey( s );
}
}
public void add( Foo f ) {
synchronized( myList ) {
myList.add( f );
// then some thing that may take a while like a database access or RPC or notifying listeners
}
}
public Thing getMedianFoo() {
Foo med = null;
synchronized( myList ) {
Collections.sort(myList);
med = myList.get(myList.size()/2);
}
return med;
}
同期ブロックの使用に関する重要な注意:ロックオブジェクトとして何を使用するかに注意してください!
上記のuser2277816のコードスニペットは、文字列リテラルへの参照がロックオブジェクトとして使用されるという点でこの点を示しています。文字列リテラルがJavaで自動的にインターンされ、問題が発生し始めることを理解してください。リテラル「ロック」で同期するすべてのコードは、同じロックを共有します。これにより、完全に関連のないコード部分でデッドロックが発生する可能性があります。
注意が必要なのは、Stringオブジェクトだけではありません。ボックス化されたプリミティブも危険です。オートボクシングとvalueOfメソッドは、値に応じて同じオブジェクトを再利用できるためです。
詳細については、https://www.securecoding.cert.org/confluence/display/java/LCK01-J.+Do+not+synchronize+on+objects+that+may+be+reusedを参照して ください。
多くの場合、メソッドレベルでロックを使用するのは失礼です。メソッド全体をロックして、共有リソースにアクセスしないコードをロックする理由。各オブジェクトにはロックがあるため、ブロックレベルの同期を実装するダミーオブジェクトを作成できます。 ブロックレベルはメソッド全体をロックしないため、より効率的です。
ここにいくつかの例
メソッドレベル
class MethodLevel {
//shared among threads
SharedResource x, y ;
public void synchronized method1() {
//multiple threads can't access
}
public void synchronized method2() {
//multiple threads can't access
}
public void method3() {
//not synchronized
//multiple threads can access
}
}
ブロックレベル
class BlockLevel {
//shared among threads
SharedResource x, y ;
//dummy objects for locking
Object xLock = new Object();
Object yLock = new Object();
public void method1() {
synchronized(xLock){
//access x here. thread safe
}
//do something here but don't use SharedResource x, y
// because will not be thread-safe
synchronized(xLock) {
synchronized(yLock) {
//access x,y here. thread safe
}
}
//do something here but don't use SharedResource x, y
//because will not be thread-safe
}//end of method1
}
[編集]
以下のためCollection
のようなVector
およびHashtable
それらが時に同期されているArrayList
かHashMap
ではなく、あなたがキーワードまたはメソッドを同期呼び出しコレクションを同期して設定する必要が:
Map myMap = Collections.synchronizedMap (myMap); // single lock for the entire map
List myList = Collections.synchronizedList (myList); // single lock for the entire list
唯一の違い:同期されたブロックは、同期された方法とは異なり、詳細なロックを可能にします
基本的に、synchronized
ブロックまたはメソッドは、メモリの不整合エラーを回避することによってスレッドセーフコードを記述するために使用されてきました。
この質問は非常に古く、過去7年間に多くのことが変更されました。スレッドセーフのために新しいプログラミング構造が導入されました。
synchronied
ブロックの代わりに高度な同時実行APIを使用することで、スレッドセーフを実現できます。このドキュメントページは、スレッドセーフを実現するための優れたプログラミング構造を提供します。
ロックオブジェクトは、多くの同時アプリケーションを簡略化するロックイディオムをサポートしています。
エグゼキュータは、スレッドを起動および管理するための高レベルAPIを定義します。java.util.concurrentによって提供されるエグゼキューター実装は、大規模なアプリケーションに適したスレッドプール管理を提供します。
並行コレクションを使用すると、データの大規模なコレクションを管理しやすくなり、同期の必要性を大幅に減らすことができます。
原子変数には、同期を最小限に抑え、メモリの一貫性エラーを回避するのに役立つ機能があります。
ThreadLocalRandom(JDK 7の場合)は、複数のスレッドから擬似乱数を効率的に生成します。
同期のより良い代替品は、API を使用するReentrantLockです。Lock
基本的な動作とセマンティクスが、同期されたメソッドとステートメントを使用してアクセスされる暗黙のモニターロックと同じですが、拡張機能を備えた、再入可能な相互排他ロック。
ロックの例:
class X {
private final ReentrantLock lock = new ReentrantLock();
// ...
public void m() {
lock.lock(); // block until condition holds
try {
// ... method body
} finally {
lock.unlock()
}
}
}
java.util.concurrentおよびjava.util.concurrent.atomicを参照してください他のプログラミング構成についてはパッケージも。
この関連する質問も参照してください:
すでにここで述べたように、同期ブロックはユーザー定義変数をロックオブジェクトとして使用できますが、同期関数は「this」のみを使用します。そしてもちろん、同期する必要がある関数の領域を操作できます。しかし、同期された関数と、「this」をロックオブジェクトとして使用して関数全体をカバーするブロックとの間に違いはないと誰もが言う。それは真実ではありません、違いは両方の状況で生成されるバイトコードにあります。同期ブロックの使用の場合は、「this」への参照を保持するローカル変数を割り当てる必要があります。その結果、関数のサイズは少し大きくなります(関数の数が少ない場合は関係ありません)。
ここで見つけることができる違いのより詳細な説明:http : //www.artima.com/insidejvm/ed2/threadsynchP.html
同期されたメソッドの場合、オブジェクトのロックが取得されます。ただし、同期ブロックを使用する場合は、ロックを取得するオブジェクトを指定するオプションがあります。
例:
Class Example {
String test = "abc";
// lock will be acquired on String test object.
synchronized (test) {
// do something
}
lock will be acquired on Example Object
public synchronized void testMethod() {
// do some thing
}
}
私はこれが古い質問であることを知っていますが、ここでの応答をざっと読んだだけで、synchronized
メソッドが誤ったロックである可能性があることを誰も言及していませんでした。
Java Concurrency In Practice(p。72)から:
public class ListHelper<E> {
public List<E> list = Collections.syncrhonizedList(new ArrayList<>());
...
public syncrhonized boolean putIfAbsent(E x) {
boolean absent = !list.contains(x);
if(absent) {
list.add(x);
}
return absent;
}
上記のコードは有する外観スレッドセーフであるのが。しかし、実際にはそうではありません。この場合、ロックはクラスのインスタンスで取得されます。ただし、そのメソッドを使用していない別のスレッドによってリストが変更される可能性があります。正しいアプローチは、
public boolean putIfAbsent(E x) {
synchronized(list) {
boolean absent = !list.contains(x);
if(absent) {
list.add(x);
}
return absent;
}
}
上記のコードは、同期ブロックが完了するまで、リストを変更しようとするすべてのスレッドがリストを変更するのをブロックします。
List
は必ずしも同期する必要はありませんコードのログがある場合、パフォーマンスの問題につながる可能性
実用的な問題として、同期化されたブロックに対する同期化されたメソッドの利点は、それらがよりばかであるということです。ロックする任意のオブジェクトを選択できないため、同期メソッドの構文を誤用して、文字列リテラルのロックや、スレッドの下から変更された変更可能なフィールドのコンテンツのロックなどの愚かなことを行うことはできません。
一方、同期メソッドでは、オブジェクトへの参照を取得できるスレッドによってロックが取得されるのを防ぐことはできません。
したがって、同期化ブロックをメソッドの修飾子として使用すると、牛のオーカーが自分自身を傷つけないように保護できます。一方、同期ブロックをプライベート最終ロックオブジェクトと組み合わせて使用すると、独自のコードを牛のオーカーから保護できます。
Java仕様の要約から:http : //www.cs.cornell.edu/andru/javaspec/17.doc.html
同期ステートメント(§14.17)は、オブジェクトへの参照を計算します。次に、そのオブジェクトに対してロックアクションを実行しようとし、ロックアクションが正常に完了するまでそれ以上処理を進めません。...
同期メソッド(8.4.3.5)は、呼び出されると自動的にロックアクションを実行します。その本体は、ロックアクションが正常に完了するまで実行されません。メソッドがインスタンスメソッドの場合、それは、それが呼び出されたインスタンス(つまり、メソッドの本体の実行中にこれと呼ばれるオブジェクト)に関連付けられたロックをロックします。メソッドがstaticの場合、メソッドが定義されているクラスを表すClassオブジェクトに関連付けられたロックをロックします。...
これらの説明に基づいて、私は以前のほとんどの答えが正しいと思います。同期されたメソッドは、静的メソッドの場合に特に役立つ可能性があります。定義されています。」
編集:私は当初、これらは実際のJava仕様の引用だと思っていました。このページは仕様の概要/説明にすぎないことを明確化
TLDR; synchronized
修飾子もsynchronized(this){...}
式も使用しませんがsynchronized(myLock){...}
、myLock
はプライベートオブジェクトを保持する最終インスタンスフィールドです。
synchronized
メソッド宣言での修飾子の使用とsynchronized(..){ }
メソッド本体での式の違いは次のとおりです。
synchronized
メソッドのシグネチャに指定された修飾子
synchronized(this) { .... }
、this
非静的メソッドで宣言されている場合はオブジェクトをロックとして使用し、静的メソッドで宣言されている場合は囲んでいるクラスを使用します。synchronized(...){...}
式により、
ただし、synchronized
修飾子またはsynchronized(...) {...}
with this
をロックオブジェクトとして使用すると(のようにsynchronized(this) {...}
)、同じ欠点があります。どちらも、同期するロックオブジェクトとして独自のインスタンスを使用します。これは危険であるため、オブジェクト自体だけでなく、任意にも潜在的に重篤な副作用(性能低下と同期ロックとして使用することができ、そのオブジェクトへの参照を保持している他の外部のオブジェクト/コードデッドロック)。
したがって、ベストプラクティスは、synchronized
修飾子もsynchronized(...)
式もthis
ロックオブジェクトとして使用せず、このオブジェクト専用のロックオブジェクトを使用することです。例えば:
public class MyService {
private final lock = new Object();
public void doThis() {
synchronized(lock) {
// do code that requires synchronous execution
}
}
public void doThat() {
synchronized(lock) {
// do code that requires synchronous execution
}
}
}
複数のロックオブジェクトを使用することもできますが、ネストして使用した場合にデッドロックにならないように特別な注意を払う必要があります。
public class MyService {
private final lock1 = new Object();
private final lock2 = new Object();
public void doThis() {
synchronized(lock1) {
synchronized(lock2) {
// code here is guaranteed not to be executes at the same time
// as the synchronized code in doThat() and doMore().
}
}
public void doThat() {
synchronized(lock1) {
// code here is guaranteed not to be executes at the same time
// as the synchronized code in doThis().
// doMore() may execute concurrently
}
}
public void doMore() {
synchronized(lock2) {
// code here is guaranteed not to be executes at the same time
// as the synchronized code in doThis().
// doThat() may execute concurrently
}
}
}
この質問は、スレッドセーフシングルトンとダブルチェックロックによるレイジー初期化の違いに関するものだと思います。特定のシングルトンを実装する必要があるときは、常にこの記事を参照します。
さて、これはスレッドセーフシングルトンです。
// Java program to create Thread Safe
// Singleton class
public class GFG
{
// private instance, so that it can be
// accessed by only by getInstance() method
private static GFG instance;
private GFG()
{
// private constructor
}
//synchronized method to control simultaneous access
synchronized public static GFG getInstance()
{
if (instance == null)
{
// if instance is null, initialize
instance = new GFG();
}
return instance;
}
}
長所:
遅延初期化が可能です。
スレッドセーフです。
短所:
- getInstance()メソッドは同期化されているため、複数のスレッドが同時にアクセスできないため、パフォーマンスが低下します。
これは、ダブルチェックロックによる遅延初期化です。
// Java code to explain double check locking
public class GFG
{
// private instance, so that it can be
// accessed by only by getInstance() method
private static GFG instance;
private GFG()
{
// private constructor
}
public static GFG getInstance()
{
if (instance == null)
{
//synchronized block to remove overhead
synchronized (GFG.class)
{
if(instance==null)
{
// if instance is null, initialize
instance = new GFG();
}
}
}
return instance;
}
}
長所:
遅延初期化が可能です。
また、スレッドセーフです。
同期キーワードのためにパフォーマンスが低下しました。
短所:
初めて、パフォーマンスに影響を与える可能性があります。
短所として。ダブルチェックのロック方式は耐えられるので、高性能マルチスレッドアプリケーションに使用できます。
詳細については、この記事を参照してください。
https://www.geeksforgeeks.org/java-singleton-design-pattern-practices-examples/
スレッドと同期しています。1)機能しないスレッドでsynchronized(this)を使用しないでください。(this)と同期すると、現在のスレッドがロックスレッドオブジェクトとして使用されます。各スレッドは他のスレッドから独立しているため、同期の調整はありません。2)コードのテストは、Mac上のJava 1.6ではメソッドの同期が機能しないことを示しています。3)synchronized(lockObj)ここで、lockObjは、同期するすべてのスレッドの共通の共有オブジェクトです。4)ReenterantLock.lock()および.unlock()が機能します。これについては、Javaチュートリアルを参照してください。
次のコードは、これらのポイントを示しています。また、ArrayListの代わりに使用されるスレッドセーフなVectorも含まれています。これは、Vectorに追加する多くのスレッドが情報を失うことはなく、ArrayListを使用するスレッドは情報を失う可能性があることを示しています。0)現在のコードは競合状態による情報の損失を示していますA)現在のラベル付きのA行をコメント化し、その上のA行のコメントを外してから実行すると、メソッドはデータを失いますが、そうすべきではありません。B)ステップAを逆にして、Bのコメントを外し、//ブロックを終了します}。次に、データを失うことなく結果を確認するために実行します。C)コメントアウトB、コメントを外します。C。実行します。(これ)で同期すると、予想どおりデータが失われます。すべてのバリエーションを完了する時間はありません。これが役立つことを願っています。(this)で同期する場合、またはメソッドの同期が機能する場合は、テストしたJavaおよびOSのバージョンを明記してください。ありがとうございました。
import java.util.*;
/** RaceCondition - Shows that when multiple threads compete for resources
thread one may grab the resource expecting to update a particular
area but is removed from the CPU before finishing. Thread one still
points to that resource. Then thread two grabs that resource and
completes the update. Then thread one gets to complete the update,
which over writes thread two's work.
DEMO: 1) Run as is - see missing counts from race condition, Run severa times, values change
2) Uncomment "synchronized(countLock){ }" - see counts work
Synchronized creates a lock on that block of code, no other threads can
execute code within a block that another thread has a lock.
3) Comment ArrayList, unComment Vector - See no loss in collection
Vectors work like ArrayList, but Vectors are "Thread Safe"
May use this code as long as attribution to the author remains intact.
/mf
*/
public class RaceCondition {
private ArrayList<Integer> raceList = new ArrayList<Integer>(); // simple add(#)
// private Vector<Integer> raceList = new Vector<Integer>(); // simple add(#)
private String countLock="lock"; // Object use for locking the raceCount
private int raceCount = 0; // simple add 1 to this counter
private int MAX = 10000; // Do this 10,000 times
private int NUM_THREADS = 100; // Create 100 threads
public static void main(String [] args) {
new RaceCondition();
}
public RaceCondition() {
ArrayList<Thread> arT = new ArrayList<Thread>();
// Create thread objects, add them to an array list
for( int i=0; i<NUM_THREADS; i++){
Thread rt = new RaceThread( ); // i );
arT.add( rt );
}
// Start all object at once.
for( Thread rt : arT ){
rt.start();
}
// Wait for all threads to finish before we can print totals created by threads
for( int i=0; i<NUM_THREADS; i++){
try { arT.get(i).join(); }
catch( InterruptedException ie ) { System.out.println("Interrupted thread "+i); }
}
// All threads finished, print the summary information.
// (Try to print this informaiton without the join loop above)
System.out.printf("\nRace condition, should have %,d. Really have %,d in array, and count of %,d.\n",
MAX*NUM_THREADS, raceList.size(), raceCount );
System.out.printf("Array lost %,d. Count lost %,d\n",
MAX*NUM_THREADS-raceList.size(), MAX*NUM_THREADS-raceCount );
} // end RaceCondition constructor
class RaceThread extends Thread {
public void run() {
for ( int i=0; i<MAX; i++){
try {
update( i );
} // These catches show when one thread steps on another's values
catch( ArrayIndexOutOfBoundsException ai ){ System.out.print("A"); }
catch( OutOfMemoryError oome ) { System.out.print("O"); }
}
}
// so we don't lose counts, need to synchronize on some object, not primitive
// Created "countLock" to show how this can work.
// Comment out the synchronized and ending {, see that we lose counts.
// public synchronized void update(int i){ // use A
public void update(int i){ // remove this when adding A
// synchronized(countLock){ // or B
// synchronized(this){ // or C
raceCount = raceCount + 1;
raceList.add( i ); // use Vector
// } // end block for B or C
} // end update
} // end RaceThread inner class
} // end RaceCondition outter class