当前位置: 首页 > 知识库问答 >
问题:

同步块不工作

陶裕
2023-03-14

这个练习直接来自SCJP,由凯西·塞拉和伯特·贝茨完成

同步代码块

在这个练习中,我们将尝试同步一个代码块。在该代码块中,我们将获得对象的锁,以便其他线程在代码块执行时无法html" target="_blank">修改它。我们将创建三个线程,它们都将尝试操作同一对象。每个线程将输出一个字母100次,然后将该字母递增一次。我们将使用的对象是StringBuffer。

我们可以在一个String对象上进行同步,但是字符串一旦创建就不能被修改,所以我们不能在不生成一个新的String对象的情况下增加字母。最终的输出应该有100个A、100个B和100个C,都在不间断的行中。

  1. 创建一个类并扩展 Thread 类。
  2. 重写线程的 run() 方法。这是同步代码块将转到的位置。
  3. 为了使我们的三个线程对象共享同一个对象,我们需要创建一个在参数中接受 StringBuffer 对象的构造函数。
  4. 同步的代码块将从步骤 3 中获取字符串缓冲区对象的锁。
  5. 在块中,输出字符串缓冲区 100 次,然后在字符串缓冲区中递增该字母。您可以查看第 6 章中是否有字符串缓冲区方法,这些方法对此有所帮助。
  6. 最后,在 main() 方法中,使用字母 A 创建一个 StringBuffer 对象,然后创建我们类的三个实例并启动所有三个实例。

我已经为上面的练习写了下面的类(而不是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');
        }
    }
}

我希望输出如下(10A、10B和10C),但没有得到。

AAAAAAAAAA
BBBBBBBBBB
CCCCCCCCCC

相反,当三个线程有机会在另一个线程完成之前进入循环时,我得到了如下不同的输出。

AAAAAAAAAAAAAAAAAA
ABB
ACCCCCCCC

我的问题是为什么run方法中的synchronized块不起作用?

共有3个答案

訾高明
2023-03-14

我也很困惑。Brian提供的答案是正确的

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

}

上面的代码将显示相同的输出,但是场景完全不同。所以在synchronized块中使用什么是非常重要的。

邹华皓
2023-03-14

您应该锁定字符串缓冲区对象

 synchronized(sb) {
            for (int i=0; i<10; i++) {
                System.out.print(sb);
            }
汪正雅
2023-03-14

4.同步的代码块将从步骤3获得StringBuffer对象上的锁。

好吧,你没有这样做,对吧?

synchronized(this) {

您正在获取调用run()方法MySyncBlockTest实例的锁。那……什么也做不了。没有对该资源的争夺;每个线程都有自己的MySyncBlockTest实例。

 类似资料:
  • 问题内容: 该练习直接由Kathy Seirra和Bert Bates撰写的SCJP 同步代码块 在本练习中,我们将尝试同步代码块。在该代码块中,我们将获得对对象的锁定,以便在代码块执行时其他线程无法修改它。我们将创建三个线程,它们都将尝试操纵同一对象。每个线程将输出一个字母100次,然后将该字母加1。我们将使用的对象是StringBuffer。 我们可以在String对象上进行同步,但是一旦创建

  • 请参阅代码。 > 当我调用方法@Async loadMarkUpPCT()时,数据没有提交到表中。它表现得好像是非牵引的。 当我从loadMarkUpPCT(类1)中删除@Async(即非异步)时,数据被提交并按预期正常:事务性) 我希望@Async和@Transactional的结果是一样的,但事实并非如此。请解释一下,我做错了什么? 编辑:我刚编辑过代码日志 流程方面:AppDataLoade

  • 问题内容: 我正在查看包含同步方法的第三方库中的一些代码,在此方法中,有一个锁定在实例变量上的同步块。与此类似: 这有意义吗?如果是这样,在同步方法中使用同步语句有什么好处? 鉴于同步方法锁定了整个对象,对我来说似乎是多余的。在使用非私有的实例变量时,这种方法是否有意义? 问题答案: 在您的示例中,该方法 同时 锁定了和的实例。其他方法可能仅锁定对象的实例 或 对象。 因此,是的,这完全取决于他们

  • 我试图使用RequestFuture向服务器发出同步请求,但它不起作用。使用异步完成相同的请求时效果良好。 这是我的代码: 我得到一个nullpointerexception: Java语言lang.NullPointerException:尝试调用虚拟方法的java。lang.String组织。json。J主题。com上的null对象引用上的toString()。数学应用程序。所有模块。在com

  • Java中的Synchronized blocks在多线程中工作时是一个很好的特性,这是非常常见的。我知道它们是如何工作的,但希望更确定它们在与等待和通知(所有)结合时是如何工作的。 通常,当一个线程进入同步块时,在第一个线程离开之前,其他线程不能进入该块。但是,当调用synchronized对象的wait时,情况就不是这样了。如果这样做了,另一个线程将无法调用notify(All),这需要在调用

  • 我试图理解java中同步块的概念。根据我读过的文档,我明白如果我们获取一个锁(使用实例变量的同步块),那么我们就不能在该类中的同一对象上获取同步锁。但是当我尝试实际使用以下片段时,我发现我的理解出了问题。 即我能够同时以两种不同的方法获取锁(同一实例变量上的同步块)。当线程启动时,它将转到run方法并无限期地等待,并且不会从同步块中出来。同时,如果我使用相同的线程调用stop方法,它会进入同步块并