简体   繁体   English

同步块不起作用

[英]Synchronized block not working

This exercise is straight out of SCJP by Kathy Seirra and Bert Bates这个练习直接来自 Kathy Seirra 和 Bert Bates 的 SCJP

Synchronizing a Block of Code同步代码块

In this exercise we will attempt to synchronize a block of code.在本练习中,我们将尝试同步代码块。 Within that block of code we will get the lock on an object, so that other threads cannot modify it while the block of code is executing.在那个代码块中,我们将获得一个对象的锁,这样在代码块执行时其他线程就不能修改它。 We will be creating three threads that will all attempt to manipulate the same object.我们将创建三个线程,它们都将尝试操作同一个对象。 Each thread will output a single letter 100 times, and then increment that letter by one.每个线程将输出单个字母 100 次,然后将该字母递增 1。 The object we will be using is StringBuffer.我们将使用的对象是 StringBuffer。

We could synchronize on a String object, but strings cannot be modified once they are created, so we would not be able to increment the letter without generating a new String object.我们可以在 String 对象上进行同步,但是字符串一旦创建就无法修改,因此如果不生成新的 String 对象,我们将无法增加字母。 The final output should have 100 As, 100 Bs, and 100 Cs all in unbroken lines.最终输出应该有 100 个 As、100 个 Bs 和 100 个 Cs,所有这些都在不间断的行中。

  1. Create a class and extend the Thread class.创建一个类并扩展 Thread 类。
  2. Override the run() method of Thread.重写 Thread 的 run() 方法。 This is where the synchronized block of code will go.这是同步代码块的位置。
  3. For our three thread objects to share the same object, we will need to create a constructor that accepts a StringBuffer object in the argument.为了让我们的三个线程对象共享同一个对象,我们需要创建一个构造函数,在参数中接受一个 StringBuffer 对象。
  4. The synchronized block of code will obtain a lock on the StringBuffer object from step 3.同步代码块将从步骤 3 中获取对 StringBuffer 对象的锁定。
  5. Within the block, output the StringBuffer 100 times and then increment the letter in the StringBuffer.在块内,输出 StringBuffer 100 次,然后递增 StringBuffer 中的字母。 You can check Chapter 6 for StringBuffer methods that will help with this.你可以查看第 6 章的 StringBuffer 方法来帮助解决这个问题。
  6. Finally, in the main() method, create a single StringBuffer object using the letter A, then create three instances of our class and start all three of them.最后,在 main() 方法中,使用字母 A 创建一个 StringBuffer 对象,然后创建我们类的三个实例并启动所有三个实例。

I have written the below class for the above exercise (instead of 100 I am printing 10 characters)我已经为上述练习编写了以下课程(而不是 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');
        }
    }
}

I was expecting an output something like the following (10 As, 10 Bs and 10 Cs) but did not get it.我期待输出类似于以下内容(10 As、10 Bs 和 10 Cs)但没有得到它。

AAAAAAAAAA
BBBBBBBBBB
CCCCCCCCCC

Instead I got varying outputs like the following as the three threads are getting a chance to get into the loop before the other has finished.相反,我得到了如下不同的输出,因为三个线程有机会在另一个线程完成之前进入循环。

AAAAAAAAAAAAAAAAAA
ABB
ACCCCCCCC

My question is why is the synchronized block in the run method not working?我的问题是为什么 run 方法中的 synchronized 块不起作用?

4. The synchronized block of code will obtain a lock on the StringBuffer object from step 3. 4. 同步代码块将从步骤 3 中获取对 StringBuffer 对象的锁定。

Well, you're not doing that, are you?好吧,你不会那样做,是吗?

synchronized(this) {

You're obtaining a lock on the instance of MySyncBlockTest on which that run() method is being called.您正在获取对MySyncBlockTest run()方法的MySyncBlockTest实例的锁定。 That ... isn't going to do anything.那……不会做任何事情。 There's no contention for that resource;没有对该资源的争用; each Thread has its own instance of MySyncBlockTest .每个Thread都有自己的MySyncBlockTest实例。

You should lock on the StringBuffer object您应该锁定 StringBuffer 对象

 synchronized(sb) {
            for (int i=0; i<10; i++) {
                System.out.print(sb);
            }

I was confused too.我也很困惑。 The answer provided by Brian is correct布赖恩提供的答案是正确的

synchronized (this){

is for getting the lock on an instance.用于获取实例的锁。 It would be useful when there is a single instance of a class and multiple threads accessing it.当有一个类的单个实例和多个线程访问它时,它会很有用。

I wrote the following program to demonstrate this:我编写了以下程序来证明这一点:

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();
}

}

The above code will display the same output but the scenario is completely different.上面的代码将显示相同的输出,但场景完全不同。 So what you use inside synchronized block is really crucial.所以你在 synchronized 块中使用的内容非常重要。

The output that you want, thats possible with multiple threads of single object, try this method您想要的输出,单个对象的多个线程是可能的,试试这个方法

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
}
 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();

}
 }

EXERCISE 13-2 from SCJP7练习 13-2 从 SCJP7

public class ThreadSyncronization extends Thread {

    StringBuffer sBuffer;
    public ThreadSyncronization(StringBuffer s,String name){
        this.sBuffer=s;
        this.setName(name);
    }
    public ThreadSyncronization(){
    }
    /**
     * @param args
     */
    public static void main(String[] args) {
        StringBuffer ch = new StringBuffer("A");
        Thread t1 = new ThreadSyncronization(ch,"first");
        Thread t2 = new ThreadSyncronization(ch,"second");
        Thread t3 = new ThreadSyncronization(ch,"third");
        t1.start();
        t2.start();
        t3.start();
    }

    public void run(){
        synchronized (sBuffer) {
            System.out.println(this.getName());
            for(int i=0;i<10;i++) {
                System.out.print(sBuffer+":"+i+" ");
                try{Thread.sleep(500);} catch(InterruptedException e) {System.out.println(e);}
            }           
            System.out.println();
            // increment char
           char c = this.sBuffer.charAt(0);
           this.sBuffer.setCharAt(0, ++c);
        }

    }

}

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));

package com.practice.ThreadPackage;包com.practice.ThreadPackage;

class ThreadParent extends Thread {类 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();

}

} }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM