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

为什么同步块给出错误的答案?

南宫泓
2023-03-14

我正在努力学习同步。根据我所了解的,下面的代码应该给出8000作为最终结果,但是我得到了一个随机的结果,如下所示;

import java.time.LocalDateTime;

public class A implements Runnable {
    String name;
    static Integer j=0;
    A(String name){
        this.name=name;
    }
    @Override
    public synchronized void  run() {
        for(int i=1;i<=1000;i++){
            synchronized(this){
            A.j++;
            }
        }
        System.out.println(j);
    }

package threads;

public class MainClass {
public static void main(String args[]){
    Thread t1=new Thread(new A("i am thread A "));
    Thread t2=new Thread(new A("i am thread B "));
    Thread t3=new Thread(new A("i am thread C "));
    Thread t4=new Thread(new A("i am thread D "));
    Thread t5=new Thread(new A("i am thread E "));
    Thread t6=new Thread(new A("i am thread F "));
    Thread t7=new Thread(new A("i am thread G "));
    Thread t8=new Thread(new A("i am thread H "));
    t1.setPriority(Thread.MAX_PRIORITY);
    t8.setPriority(Thread.MIN_PRIORITY);
    t1.start();
    t2.start();
    t3.start();
    t4.start();
    t5.start();
    t6.start();
    t7.start();
    t8.start();
    try {
        t1.join();
        t2.join();
        t3.join();
        t4.join();
        t5.join();
        t6.join();
        t7.join();
        t8.join();
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }


}
}

还是得到1293 2214 1403 3214 4214 5214 6224 7037这样的输出有没有人能给我解释一下如何实现同步,这里出了什么问题?

共有3个答案

慕项明
2023-03-14

代码中有几个问题。

> < li>

问题1:在< code>synchronized(..)不在所有线程实例之间共享

第2期:< code > system . out . println(j);行应该在< code>t8.join()之后结束;否则,您将获得8倍的输出。

修正代码

public class A implements Runnable {

    String name;
    static Integer j = 0;

    static Object lockObject = new Object();

    A(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        for (int i = 1; i <= 1000; i++) {
            synchronized (lockObject) {
                A.j++;
            }
        }
    }


    public static void main(String args[]) {
        Thread t1 = new Thread(new A("i am thread A "));
        Thread t2 = new Thread(new A("i am thread B "));
        Thread t3 = new Thread(new A("i am thread C "));
        Thread t4 = new Thread(new A("i am thread D "));
        Thread t5 = new Thread(new A("i am thread E "));
        Thread t6 = new Thread(new A("i am thread F "));
        Thread t7 = new Thread(new A("i am thread G "));
        Thread t8 = new Thread(new A("i am thread H "));
        t1.setPriority(Thread.MAX_PRIORITY);
        t8.setPriority(Thread.MIN_PRIORITY);
        t1.start();
        t2.start();
        t3.start();
        t4.start();
        t5.start();
        t6.start();
        t7.start();
        t8.start();
        try {
            t1.join();
            t2.join();
            t3.join();
            t4.join();
            t5.join();
            t6.join();
            t7.join();
            t8.join();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println(A.j);

    }
}
符功
2023-03-14

这将解决问题。您必须使用共享锁对所有线程进行< code>synchronize,因为您正在递增一个静态字段。否则,每个对象将拥有自己的锁,并并行递增静态字段,从而导致竞争情况。这就是为什么你没有得到正确的值,在这个例子中是8000。

package bookmarks;

public class A implements Runnable {
    String name;
    static Integer j = 0;
    private static Object lock = new Object();

    A(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        for (int i = 1; i <= 1000; i++) {
            synchronized (lock) {
                A.j++;
            }
        }
        System.out.println(j);

    }

}
傅边浩
2023-03-14

认为synchronized表示“关键部分”,并且在同步块运行时不会运行其他线程,这是一个常见的错误。但是,同步块只对锁定在同一锁上的其他同步块具有独占性。

你得到的答案(“使用普通锁”)是对的,但没有真正告诉你为什么。另一个常见的错误是认为< code>synchronized是保护代码,而实际上你应该考虑它保护数据。任何共享的可变数据都应该由一个锁来保护,并且只有一个锁,你应该确切地知道那个锁是什么。(您的锁定方案越复杂,您就越不可能知道什么锁保护什么数据。)因此,您应该始终考虑“数据X由锁L保护”,然后确保无论何时访问(读或写)该数据时都获得锁L。

 类似资料:
  • 问题内容: 我正在尝试运行以下内容。 如果我删除以下行: 至.... 一切都会正常。如果没有,我得到以下错误: 命令不同步; 您现在不能运行此命令 在研究,我认为这可能是由于多个库MySQLi查询同时运行,其中使用但在所有样品和通用数据导向似乎并不适用。 有任何想法吗? 问题答案: MySQL客户端不允许您执行新的查询,在该查询中仍需要从正在进行的查询中获取行。有关常见错误,请参见MySQL文档中

  • 我正在使用python 2.7。win8上的9。当我尝试使用matplotlib绘图时,出现以下错误: 从pylab导入* 绘图([1,2,3,4]) [matplotlib.lines.Line2D对象位于0x0392A9D0] 我尝试了测试代码“python simple_plot.py--verbose help”,出现了以下警告: $HOME=C:\Users\XX matplotlib数

  • 给定一个0和1的数组,我们最多可以将K个值从0更改为1。 返回仅包含1的最长(连续)子数组的长度。 例1: 例2: 注: https://leetcode.com/problems/max-consecutive-ones-iii/ 这是问题链接。在第一个测试用例中,我得到了输出9,但应该是6。我不知道哪里出了问题?

  • 问题内容: 我已经开始学习线程同步。 同步方法: 同步块: 什么时候应该使用方法和块? 为什么块比方法更好? 问题答案: 这不是更好的问题,只是有所不同。 同步方法时,实际上是在与对象本身进行同步。对于静态方法,您正在同步到对象的类。因此,以下两段代码以相同的方式执行: 就像您写的一样。 如果要控制到特定对象的同步,或者只想将方法的 一部分 同步到该对象,则指定一个块。如果在方法声明上使用关键字,

  • 我使用下面的代码来格式化日期。但是当我以不正确的格式给出数据时,它会给出意想不到的结果。 在上述情况下,输出为-formattedVal:0009-02-05。 它不是抛出解析异常,而是解析值并给我一个不正确的输出。有人能帮我理解这种反常的行为吗。