简体   繁体   English

Java布尔对象中的值赋值是否会导致在内存中重新分配

[英]Will the assignment of value in a Java Boolean object cause re-allocation in memory

I have the following piece of code 我有以下代码

Boolean flag = new Boolean(false);
flag = true;

Will the second line (assignment) cause a recreation of the initial object (basically a call to new()) in the JVM? 第二行(赋值)是否会在JVM中重新创建初始对象(基本上是对new()的调用)? I am asking because I am using a Boolean object to synchronize multiple threads, and I am afraid that if a re-initialization takes places, the waiting threads will not see the change in value. 我问,因为我使用一个布尔对象来同步多个线程,我担心如果重新初始化发生,等待线程将看不到值的变化。

In my application, there are multiple threads that are given a reference to the previous Boolean object. 在我的应用程序中,有多个线程被赋予对前一个Boolean对象的引用。 Only one thread changes the objects value to true, and the rest wait until the object's value becomes true. 只有一个线程将对象值更改为true,其余线程等待对象的值变为true。 So, if T1 is the thread that changes the value, its code is like: 因此,如果T1是更改值的线程,则其代码如下:

synchronized(flag) {
    flag = true;
    flag.notifyAll();
}

and the rest of the threads (T2) will have code like: 其余的线程(T2)将具有如下代码:

synchronized(flag) {
    while(flag == false)
        wait();
    if(flag == true) {
        //do something
    }
}

Therefore, the question is that after the assignment of true to flag, will the other threads (T2) still have access to the original object? 因此,问题是在赋值为true之后,其他线程(T2)是否仍然可以访问原始对象?

Thanks, Nick 谢谢,尼克

The assignment flag = false is a boxing conversion . 赋值flag = false装箱转换 It will get compiled as flag=Boolean.valueOf(false) which will end up returning the constant Boolean.FALSE . 它将被编译为flag=Boolean.valueOf(false) ,最终将返回常量Boolean.FALSE

So the answer is, it will not create a new object but it will change the variable flag as it assigns an instance distinct from your previous result of new Boolean(false) . 所以答案是,它不会创建一个新对象,但会更改变量flag因为它会分配一个与之前的new Boolean(false)结果不同的实例new Boolean(false)

It's not quite clear what you are actually doing but in general, synchronizing on a mutable variable is broken design. 目前还不是很清楚你实际在做什么,但一般来说,在可变变量上进行同步就是破坏设计。


The problem is that you are mixing the value that makes up your condition and the object to synchronize on. 问题是您正在混合构成条件的值和要同步的对象。 The simplest implementation of your updated intention is to use a simple boolean flag and synchronize on the instance that contains the flag: 更新后的最简单的实现是使用一个简单的boolean标志并在包含该标志的实例上进行同步:

class WithFlag {
  private boolean flag;

  public synchronized void setToTrue() {
    if(!flag) {
      flag=true;
      notifyAll();
    }
  }
  public synchronized void waitForTrue() throws InterruptedException {
    while(!flag) wait();
  }
}

Note that declaring an instance method synchronized is similar to wrap its code with synchronized(this) { … } 请注意,声明synchronized的实例方法类似于使用synchronized(this) { … }包装其代码

如果要使用布尔值来同步线程,则应考虑使用专门为此目的而设计的AtomicBoolean

The other answers have already explained that when you say flag=false , it is a boxing conversion which will return the constant Boolean.FALSE . 其他答案已经解释过,当你说flag=false ,它是一个装箱转换,它将返回常量Boolean.FALSE One important point that the other answers have covered but not emphasized on is that when you obtain a lock on two Boolean objects that were assigned the same value through a boxing conversion, it is as good as obtaining a lock on one Boolean object. 其他答案已经涵盖但未强调的一个重点是,当您通过装箱转换获得两个布尔对象的锁定时,它就像在一个布尔对象上获得锁定一样好。

My answer attempts to give an example to explain this. 我的回答试图举一个例子来解释这一点。 Consider the following code that creates two threads that obtain a lock on a Boolean. 请考虑以下代码,该代码创建两个获取布尔值锁定的线程。

public class BooleanTest {

    public static void main(String[] args) {
        BooleanTest test = new BooleanTest();
        test.booleanTest();

    }

    private void booleanTest() {
        BooleanLockTester booleanLock1 = new BooleanLockTester();
        booleanLock1.setBooleanLock(true);
        BooleanLockTester booleanLock2 = new BooleanLockTester();
        booleanLock2.setBooleanLock(true);
        BooleanLocker booleanLocker1 = new BooleanLocker(booleanLock1);
        BooleanLocker booleanLocker2 = new BooleanLocker(booleanLock2);

        Thread threadOne = new Thread(booleanLocker1);
        Thread threadTwo = new Thread(booleanLocker2);

        threadOne.start();
        threadTwo.start();
    }

    private class BooleanLocker implements Runnable {

        private BooleanLockTester booleanLockObj;

        public BooleanLocker(BooleanLockTester booleanLockObj) {
            this.booleanLockObj = booleanLockObj;
        }

        @Override
        public void run() {
            booleanLockObj.testLockOnBoolean();
        }

    }

    private class BooleanLockTester {

        private Boolean booleanLock = false;

        public synchronized void testLockOnBoolean() {
            synchronized (booleanLock) {
                for (int i = 0; i<1000000000; ++i) {
                    System.out.println(Thread.currentThread().getName());
                }
            }
        }

        public void setBooleanLock(Boolean booleanLock) {
            this.booleanLock = booleanLock;
        }

    }
}

In the above example, the two threads will never be able to enter the for loop together. 在上面的例子中,两个线程永远不能一起进入for循环。 When you run the program, you will see that the thread that starts first will start printing on the console and only when it is finished, the next thread will start printing to the console. 当您运行程序时,您将看到首先启动的线程将在控制台上开始打印,并且只有在完成后,下一个线程才会开始打印到控制台。

Let's make a small change in the above code : Change the following line in the code : 让我们在上面的代码中做一个小改动:更改代码中的以下行:

booleanLock2.setBooleanLock(true);

To this : 对此:

booleanLock2.setBooleanLock(false);

You will now see that the threads stop behaving and print to the console in a random order. 您现在将看到线程停止运行并以随机顺序打印到控制台。 This is because the threads now obtain a lock on two different objects. 这是因为线程现在获得了对两个不同对象的锁定。

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

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