12

この演習は、キャシー・セイラとバート・ベイツによる SCJP からそのまま引用したものです。

コード ブロックの同期

この演習では、コード ブロックの同期を試みます。そのコード ブロック内でオブジェクトのロックを取得し、コード ブロックの実行中に他のスレッドがオブジェクトを変更できないようにします。すべて同じオブジェクトを操作しようとする 3 つのスレッドを作成します。各スレッドは 1 つの文字を 100 回出力し、その文字を 1 ずつ増やします。使用するオブジェクトは StringBuffer です。

String オブジェクトで同期することはできますが、作成された文字列は変更できないため、新しい String オブジェクトを生成せずに文字をインクリメントすることはできません。最終的な出力には、100 個の As、100 個の B、および 100 個の C がすべて切れ目のない行で含まれている必要があります。

  1. クラスを作成し、Thread クラスを拡張します。
  2. Thread の run() メソッドをオーバーライドします。これは、コードの同期ブロックが移動する場所です。
  3. 3 つのスレッド オブジェクトが同じオブジェクトを共有するには、引数で StringBuffer オブジェクトを受け入れるコンストラクターを作成する必要があります。
  4. 同期されたコード ブロックは、手順 3 から StringBuffer オブジェクトのロックを取得します。
  5. ブロック内で、StringBuffer を 100 回出力してから、StringBuffer 内の文字をインクリメントします。これに役立つ StringBuffer メソッドについては、第 6 章を参照してください。
  6. 最後に、main() メソッドで、文字 A を使用して単一の StringBuffer オブジェクトを作成し、クラスの 3 つのインスタンスを作成して、3 つすべてを開始します。

上記の演習用に以下のクラスを作成しました (100 文字ではなく、10 文字を印刷しています)。

class MySyncBlockTest extends Thread {

    StringBuffer sb;

    MySyncBlockTest(StringBuffer sb) {
        this.sb=sb;
    }

    public static void main (String args[]) {
        StringBuffer sb = new StringBuffer("A");
        MySyncBlockTest t1 = new MySyncBlockTest(sb);
        MySyncBlockTest t2 = new MySyncBlockTest(sb);
        MySyncBlockTest t3 = new MySyncBlockTest(sb);
        t1.start();
        t2.start();
        t3.start();
    }

    public void run() {
        synchronized(this) {
            for (int i=0; i<10; i++) {
                System.out.print(sb);
            }
            System.out.println("");
            if (sb.charAt(0)=='A')
                sb.setCharAt(0, 'B');
            else
                sb.setCharAt(0, 'C');
        }
    }
}

次のような出力 (10 As、10 B、10 C) を期待していましたが、取得できませんでした。

AAAAAAAAAA
BBBBBBBBBB
CCCCCCCCCC

代わりに、次のようなさまざまな出力が得られました。これは、3 つのスレッドが他のスレッドが終了する前にループに入る機会を得ているためです。

AAAAAAAAAAAAAAAAAA
ABB
ACCCCCCCC

私の質問は、run メソッドの同期ブロックが機能しないのはなぜですか?

4

8 に答える 8

21

4. 同期されたコード ブロックは、手順 3 から StringBuffer オブジェクトのロックを取得します。

ええと、あなたはそうしていませんよね?

synchronized(this) {

MySyncBlockTestそのrun()メソッドが呼び出されているインスタンスのロックを取得しています。それは…どうにもなりません。そのリソースには競合はありません。それぞれThreadに の独自のインスタンスがありMySyncBlockTestます。

于 2013-08-03T05:44:33.847 に答える
4

StringBuffer オブジェクトをロックする必要があります

 synchronized(sb) {
            for (int i=0; i<10; i++) {
                System.out.print(sb);
            }
于 2013-08-03T05:50:08.037 に答える
2

私も混乱しました。ブライアンが提供した答えは正しいです

synchronized (this){

インスタンスのロックを取得するためのものです。クラスのインスタンスが 1 つしかなく、それに複数のスレッドがアクセスしている場合に便利です。

これを実証するために、次のプログラムを作成しました。

package com.threads.chapter9;

public class TestSunchronizedBlocksUsingRunnable implements Runnable {
StringBuffer s;

@Override
public void run() {
    synchronized (this) {
        for (int i = 1; i <= 100; i++) {
            System.out.println(i);
        }
        char c = s.charAt(0);
        c++;
        s.setCharAt(0, c);
    }
}

TestSunchronizedBlocksUsingRunnable(StringBuffer s) {
    this.s = s;
}

public static void main(String[] args) {
    StringBuffer s = new StringBuffer("A");
    TestSunchronizedBlocksUsingRunnable instance1 = new TestSunchronizedBlocksUsingRunnable(s);
    Thread thread1 = new Thread(instance1);
    Thread thread2 = new Thread(instance1);
    Thread thread3 = new Thread(instance1);
    thread1.start();
    thread2.start();
    thread3.start();
}

}

上記のコードは同じ出力を表示しますが、シナリオは完全に異なります。したがって、同期ブロック内で使用するものは非常に重要です。

于 2016-05-06T15:12:55.760 に答える
1

必要な出力は、単一オブジェクトの複数のスレッドで可能です。このメソッドを試してください

public class MultiThreading implements Runnable {
public static void main(String [] arg)
{
MultiThreading a=new MultiThreading(20);
Thread t0=new Thread(a);   //
Thread t1=new Thread(a);   // Multiple Threads of single object
Thread t2=new Thread(a);   // 
t0.start();
t1.start();
t2.start();
}
private int count;
MultiThreading(int a)
{this.count=a;
}
public void run()
{
synchronized(this){   
String t_name=new String("");
t_name=Thread.currentThread().getName().toString();
    for(int i=0;i<count;i++)
    if(t_name.equals("Thread-0".toString())) // mean t0
        System.out.print("A");

    else if(t_name.equals("Thread-1".toString())) // mean t1
        System.out.print("B");

    else if(t_name.equals("Thread-2".toString())) // mean t1
        System.out.print("C");
System.out.print("\n");
                  }
} // end of run
}
于 2013-12-01T13:08:42.513 に答える
-1
 EXERCISE 9-2 from SCJP:
Try this For Synchronozing on stringBuffer Object.
It is giving required output.




class letterThread extends Thread
{
StringBuffer putLetter;

letterThread(StringBuffer str)
{
    this.putLetter=str;
}

public void run()
{

    synchronized (putLetter) {

        if(Thread.currentThread().getName().equals("th2"))
        {
            this.putLetter=new StringBuffer("B");
        }
        else if(Thread.currentThread().getName().equals("th3"))
        {
            this.putLetter=new StringBuffer("C");
        }

        for(int i=1;i<11;i++)
        {
            System.out.print(putLetter+"");
        }
        System.out.println();
    }
}   
}

public class Manager
{
public static void main(String args[])
{
    StringBuffer str=new StringBuffer("A");
    letterThread th1=new letterThread(str);
    letterThread th2=new letterThread(str);
    letterThread th3=new letterThread(str);

    th1.setName("th1");
    th2.setName("th2");
    th3.setName("th3");

    th1.start();
    th2.start();
    th3.start();

}
 }
于 2014-05-15T11:14:34.480 に答える
-2

You could replace

        if (sb.charAt(0)=='A')
            sb.setCharAt(0, 'B');
        else
            sb.setCharAt(0, 'C');

with

sb.setCharAt(0, (char) (sb.charAt(0) + 1));
于 2015-02-06T11:07:22.127 に答える
-4

パッケージcom.practice.ThreadPackage;

クラス ThreadParent はスレッドを拡張します {

StringBuffer data;

public void run() {
    synchronized (this.data) {

        System.out.println(this.getName());

        for (int i = 0; i < 10; i++) {

            System.out.print(this.data.toString());
        }

        System.out.println();
        this.data.setCharAt(0, ((char) (this.data.charAt(0) + 1)));
    }
}

ThreadParent(StringBuffer obj) {
    this.data = obj;
}

}

public class ThreadClass { public static void main(String args[]) {

    StringBuffer str = new StringBuffer("A");
    ThreadParent obj = new ThreadParent(str);
    ThreadParent obj1 = new ThreadParent(str);
    ThreadParent obj2 = new ThreadParent(str);
    obj.setName("Thread1");
    obj1.setName("Thread2");
    obj2.setName("Thread3");
    obj.start();
    obj1.start();
    obj2.start();

}

}

于 2015-02-07T18:57:58.540 に答える