Discuss / Java / 请教廖老师,单行return为什么不是原子操作呢?

请教廖老师,单行return为什么不是原子操作呢?

Topic source

无故之秋

#1 Created at ... [Delete] [Delete and Lock User]

public class TestMain {

    public static void main(String[] args) {

        Point point = new Point();

        point.set(100, 200);

        Thread t1 = new Thread(() -> {

            point.set(110, 220);

        });

        Thread t2 = new Thread(() -> {

            System.out.println(point.get());

        });

        t2.start();

        t1.start();

    }

}

class Point {

    @Override

    public String toString() {

        return "Point{" +

                "x=" + x +

                ", y=" + y +

                '}';

    }

    int x;

    int y;

    public void set(int x, int y) {

        synchronized (this) {

            this.x = x;

            try {

                Thread.sleep(100);

            } catch (InterruptedException e) {

                throw new RuntimeException(e);

            }

            this.y = y;

        }

    }

    public Point get() {

//        int[] copy = new int[2];

//        copy[0] = x;

//        copy[1] = y;

//        return copy;

        return this;

    }

}

有时执行会得到Point{x=110, y=200}的结果。

为什么get()方法不是原子操作呢?

对着剑说

#2 Created at ... [Delete] [Delete and Lock User]

这不是多线程并发,没有执行同一个任务

对着剑说

#3 Created at ... [Delete] [Delete and Lock User]

return "Point{" +

                "x=" + x +

                ", y=" + y +

                '}';
可能是先执行了get方法中获取y值得部分,再执行了set方法

但我没有理解为什么是获取y,

也就是说,这句代码可以拆分成哪些指令,我并不太清楚

之前,我的回复有问题,没有理解清楚这个问题,但无法删掉,不希望给大伙儿带来误会

路人

#4 Created at ... [Delete] [Delete and Lock User]

我的理解是return 语句本身是原子的,但返回的是Point对象的引用。

此时,另一个线程已经修改了x,在sleep等待状态。

当执行打印输出时,即是Point{x=110, y=200}的结果

原因是toString没加锁。

public class Main {
    public static void main(String[] args) throws InterruptedException {
        Point point = new Point();
        point.set(100, 200);
        Thread t1 = new Thread(() -> {
            point.set(110, 220);
        });
        System.out.println(point);
        t1.start();
        t1.join(1);
        System.out.println(point);
    }
}
class Point {
    @Override
    public String toString() {
        return "Point{x=" + x + ", y=" + y + '}';
    }
    int x,y;
    public void set(int x, int y) {
        synchronized (this) {
            this.x = x;
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            this.y = y;
        }
    }
}

不加锁两个打印基本没有间隔时间。

```public String toString() {

        String s;

        synchronized (this) {

            s = "Point{x=" + x + ", y=" + y + '}';

        }

        return s;

    }

加锁后,会等待get执行完毕。


  • 1

Reply