ホームページ  >  記事  >  Java  >  初心者向けJava学習メモ(8)

初心者向けJava学習メモ(8)

黄舟
黄舟オリジナル
2016-12-20 13:54:131218ブラウズ

22 日のメモに質問がありませんでしたか? 私がコンパイルしたプログラムに非同期が存在しないのはなぜですか? 現在、この問題は基本的に解決されています

返信者: bluesmile979 (笑) ( ) 評判: 100 2003-01-22 21:08:00 スコア: 0
私の意見を言わせてください、あなたのコードを読んだ後、最大の問題はマルチスレッドであると思います。 2行しかありません。この例では、複数のスレッドがタイム スライスをめぐって競合する場合、当然、中断される可能性が大幅に高くなります。ループを追加したとしても、マシンの計算速度の関係で、複数のスレッド間の競合ほど明らかではありません。あなたがどう思っているかわかりません。

返信者: xm4014(forrest) ( ) 評判: 100 2003-01-22 22:07:00 スコア: 0
bluesmile979 さんへ(笑)
スレッドが少なすぎるのが原因なのかとも考えましたが、 Java ルーチンの両方のパラメータを 1 に設定して実行すると、最終的には私が作成したプログラムと同じになり、結果はまだ同期していません。
返信者:tianfeichen (よく聞いてください) ( ) 評判: 110 2003-01-22 23:57:00 スコア: 0
スレッドの配置は結局ランダムです 同期が外れることはまれです。数が少ないと、見つけるのは簡単ではありません。
私の通常の方法は、ループ中に出力を必要とせずに、最初に無限ループを開始することです。次のような停止条件を追加します。
if (counter1 != counter2)
{
System.out.PRintln( counter1 + " ," + counter2)
System.exit(0);
}
あとは待つだけです。通常、結果は 10 秒以内、場合によっては数秒以内に表示されます。カウントが数十万または数百に達していることがわかります。 。 全体として。
同時に 5 つのスレッドが開かれ、1 分間待機すると、同期されたと見なされます。

私の方法はあまり科学的ではないかもしれませんが、効果はかなり良いです。

返信者: xm4014(forrest) ( ) 評判: 100 2003-01-23 11:44:00 スコア: 0
デバッグを手伝ってくれませんか?あなたの方法に従っても結果が得られないのはなぜですか?
次のコードを直接コピーするだけです。プログラム名は Sharing2.java、バージョンは 1.4.1 です
class TwoCounter extends Thread {
private int count1 = 0, count2 = 0;
private boolean starting=false;
public void start (){
if (!started)
{
started=true;
super.start();
}
}
public void run() {
while (true) {
count1++;
count2++;
// システム.out.println("Count1="+count1+",Count2="+count2);
try {
sleep(500);
} catch (InterruptedException e){System.out.println("TwoCounter.run") ; }
}
}

public void synchTest() {
// Sharing2.incrementaccess();
if(count1 != count2)
{System.out.println(count1+","+count2);
システム終了(0);
}
}
}

class Watcher extends Thread {
private Sharing2 p;
public Watcher(Sharing2 p) {
this.p = p;
start();
}
public void run( ) {
while(true) {
p.s.synchTest();
try {
sleep(500);
} catch (InterruptedException e){System.out.println("Watcher.run");}
}
}
}

public class Sharing2 {
TwoCounter s;
private static int accessCount = 0;
public static void incrementAccess() {
// accessCount++;
// System.out.println("accessCount="+accessCount);
}
public static void main(String[] args) {
Sharing2 aaa = new Sharing2();
aaa.s=new TwoCounter();
aaa.s.start();
new Watcher(aaa);
}
} ///:~

なお、あなたの見方では、私のプログラムには問題はありませんが、スレッドが少なく、非同期が発生しにくいのはカウンターが 1 まで増加した場合のみです。たくさんありますよね?

返信者: hey_you(Hey) ( ) レピュテーション: 100 2003-01-23 13:27:00 スコア: 0

これは私が考えていることです: 同期の欠如による競合の可能性があり、同期によりこの可能性が許可されますは0です。同期外れを発見しなかったからといって、同期外れが決して起こらないことを証明することはできません。それは時間の問題です。システムのスレッド スケジューリングは環境の影響を受けます。マシン上で同時に多数のプログラムが実行されている場合は、状況が異なる場合があります。

Replyee: xm4014(forrest) ( ) Reputation: 100 2003-01-23 15:56:00 Score: 0
はは、tianfeichen メソッドを使用してプログラムを実行しました。これは、上に投稿したコードです。実際に結果があります。 , counter1=217327, counter2=217356, かなり違うと思います。しかし、その時間は決して1分や2分という単純なものではなく、私と彼の動作環境の違いによるものかもしれません。

これ以上議論する必要がないと思われる場合は、投稿を受け入れます。 38:00 スコア: 0
1 ~ 2 時間粘っていただければ、テストを受けます。

問題の結果はたったの2点だと思います。 1 つは、私が考えるスレッドの数です

もう 1 つは、setText がより多くの処理を実行し、より多くのリソースを占有すると思われるスレッドの数です。

どちらの状況も、この問題の発生確率に影響します:) 要約しましょう、笑。

返信者: linliangyi (Blue Mountain Coffee) ( )評判: 100 2003-01-23 17:10:00 スコア: 0
sleep (500) は (5000) よりも時間がかかるため、スレッドはスリープ状態になります。スイッチインされる確率は、中断される確率よりもはるかに優れています。 ! (私のプログラムを見返すとわかります)

実際、2 つの変数が等しくないから等しいに変化したという事実は、それらが同期していないことを示しています。 !

ちなみに、setTextなどのスレッド内でswingやawtコントロールを操作すると事故が多発します
著者の関連書籍も読めます! !

回答者: xm4014(forrest) ( ) 評判: 100 2003-01-24 14:25:00 スコア: 0
皆さんの意見をまとめてみます:

まず確認すべきことは、使用しない場合はsynchronized キーワードは、同期メソッドまたは同期ブロックを定義するために使用されます。一方、synchronized では、この可能性が 0 になります。

最初のケースでは、非同期が発生する可能性がありますが、その確率は次のとおりです。以下の要因の影響を受けます
1. オペレーティング システムや動作環境が異なると、非同期を検出する確率が異なる場合があります。また、待機時間が異なる場合があります。 2. プログラム内のスレッド数が少なすぎる場合。 3. コード自体の影響により、awt クラスのメソッドで GUI を使用すると、より多くのリソースが消費され、多くのエラーが発生する可能性があります。事故が発生するため、競合の可能性が非常に高くなります
4. スレッドはオペレーティング システムによってランダムに割り当てられ、本質的に不確実性が存在します。この不確実性は最終結果にも影響します

それが正しいかどうかはわかりません。他に追加できますか?
この投稿は明日正式に終了します

しかし、正直に言うと、私のプログラムによると、最終結果 counter1 (217327) と counter2 (217356 ) がなぜこれほど異なるのか少し混乱しています。 2 つの自己増加ステートメントの間にウォッチャー スレッドが挿入された場合でも、検出される 2 つのカウンタの差は最大 1 です。このような大きな違いは、あるカウンタの自己増加ステートメントが強制的に中断された場合にのみ発生します。他のスレッドの存在が現在のスレッドに干渉することはありますが、ステートメントは実行されません。できることは待ってから再度実行することです。少し混乱しています。よろしければ、説明していただけませんか。その結果、新たな問題が発生しました。答えは明日までわかりません

でも、今日は同期に関する別の問題を解決できます。解決できないからこそ、解決する必要があると思います。戻ってよく勉強してください スレッドと同期に関する質問は次のとおりです:

file://このプログラムを分析して、synchronized、wait()、notify に焦点を当てて説明します。ありがとうございます。
class ThreadA
{
public static void main(String[] args)
{
ThreadB b=new ThreadB();
b.start();
System.out.println("b は start...." );
synchronized(b)//括弧内の b は何を意味し、どのような役割を果たしますか?
{
try
{
System.out.println("Waiting for b to complete...");
b. wait ();//この文は何を意味しますか?誰が待つべきですか?
System.out.println("Completed.Now back to main thread");
}catch (InterruptedException e){}
}
System.out. println("合計は :"+b.total);
}
}

class ThreadB extends Thread
{
int total;
public void run()
{
synchronized(this)
{
System.out.println ("スレッド B が実行中です。");
for (int i=0;i{
total +=i;
System.out.println("total is "+total);
}
このプログラムを分析するには、まず、notify() と wait() を理解する必要があります。なぜなら、これら 2 つのメソッドは、数日前にスレッドを記録したときに記録されなかったのです。もともと Thread クラスに属しているのではなく、最下位の基本オブジェクト クラスに属しているのです。つまり、Thread だけでなく、すべてのオブジェクトが notify 関数と wait 関数を持っています。ロックはロックを操作するために使用され、すべてのオブジェクトにはロックがあるため、ロックは基本的なものであるため、当然、ロックを操作する方法も最も基本的なものになります。何よりも、「Java 14.3.1 で考える」のパート 3: 待機と通知、つまり wait() と通知を確認するのが最善です。

「Java で考える」の説明によると、「wait() を使用するとスレッド化が可能になります。」スレッドを「スリープ」状態にし、同時に条件が変更されるのを「アクティブに」待ちます。そして、notify() または NoticeAll() が変更された場合にのみ、スレッドが起動されて、条件が変更されたかどうかを確認します。 「

この文を説明しましょう。
「wait() を使用すると、スレッドを「スリープ」状態にできます。」 つまり、wait は現在のスレッドもブロックします。これは、スリープまたはサスペンドと同じです。スリープと同じですが、サスペンドとの違いは何ですか?

違いは、「(wait) は条件が変化するのを同時に「アクティブに」待機することです。これは非常に重要です。スリープとサスペンドではこれができません。スレッド間の競合を防ぐために同期の助けが必要になる場合があるためです。同期を使用すると、オブジェクトはロックされている必要があります。つまり、オブジェクト ロックを使用する他のスレッドは、同期メソッドまたは同期ブロック内のすべてのプログラムが実行されるまで待機する必要があります。同期されたブロックは、sleep() もsuspend() も、呼び出されたときにロックを解除できません。どちらも使用中のオブジェクト ロックを占有しますが、wait は同期メソッドまたは同期ブロックを一時的に放棄して一時的にロックを解除することができます。これは、他の特定の状況下では (sleep!)、wait() の実行中に、スレッド オブジェクト内の他の同期メソッドを呼び出すことができることを意味します。 、サスペンド)、これは不可能です
しかし、私がオブジェクトのロックを一時的に放棄し、それを他のスレッドに一時的に使用するだけであることに注意してください、待機しているスレッドはまだオブジェクトのロックを取り戻す必要があります。 . 待って、他の人が使用した後に返してください。
それでは、オブジェクトのロックを取り戻すにはどうすればよいでしょうか?
1 つ目の方法は、wait(1000) などの貸し出し時間をミリ秒単位で設定することです。つまり、1 秒だけ貸し出します。 2 番目の方法は、貸してくれた人に「使い終わったので返してほしい」と連絡してもらいます。この時点ですぐに返します。 、私が設定した場合は1時間後に取り戻しましたが、他の人は完了するまでに30分しかかかりませんでした。もちろん、どれだけ長く設定しても、使用後に取り戻しました。
それでは、他の人はどうやって私に通知するのでしょうか? 私はそれを信じています。これは、最後の文の「notify() または NoticeAll() が変更された場合にのみ起動されます。」の意味です。 、スレッド関連の処理がそのクラスで準備されているかどうかに関係なく、同期メソッドまたは同期ブロック内に配置される wait() と Notice() を使用できます。そして実際には、同期メソッドまたは同期ブロック内でのみ wait() と Notice() を呼び出すことができます。

現時点では、上記のプログラムを説明するのは簡単です。

synchronized(b){... } ; 同期ブロックを定義し、b をリソース ロックとして使用することを意味します。 b.wait(); は、同じロックを使用している他のスレッドが実行できるように、ロックを一時的に解放して現在のスレッドをブロックすることを意味します。特定の時点まで実行されないようにするには、notify() を使用して、ロックが使い果たされたことを wait のスレッドに通知します。

以上は Java を学ぶ初心者向けのメモ (8) の内容です。その他の関連コンテンツについては、PHP 中国語 Web サイト (www.php.cn) に注目してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。