Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/386.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 为什么可以';当只使用getter和setter时,线程不是不安全的类工作吗?_Java_Multithreading_Thread Safety_Synchronized - Fatal编程技术网

Java 为什么可以';当只使用getter和setter时,线程不是不安全的类工作吗?

Java 为什么可以';当只使用getter和setter时,线程不是不安全的类工作吗?,java,multithreading,thread-safety,synchronized,Java,Multithreading,Thread Safety,Synchronized,我的课程如下: public class BoolFlag { boolean flag; public BoolFlag() { flag=false; } public synchronized void setFlag(boolean flag) { this.flag=flag; } public synchronized boolean getFlag() { return flag; } } 如果不将getter和setter设置为同步,则会导致以下问

我的课程如下:

public class BoolFlag
{
boolean flag;

public BoolFlag()
{
    flag=false;
}

public synchronized void setFlag(boolean flag)
{
    this.flag=flag;
}

public synchronized boolean getFlag()
{
    return flag;
}
}
如果不将getter和setter设置为同步,则会导致以下问题:

public class BoolFlag
{
boolean flag;

public BoolFlag()
{
    flag=false;
}

public synchronized void setFlag(boolean flag)
{
    this.flag=flag;
}

public synchronized boolean getFlag()
{
    return flag;
}
}
当我在一个按钮中设置名为imageready的BoolFlag对象时,单击listiner:

 if (status == JFileChooser.APPROVE_OPTION)
           { 
               try
               {
                    System.out.println("File chosen");
                    imgFile=chooser.getSelectedFile();  
                    image.setImg( ImageIO.read(imgFile) );
                    imageready.setFlag(true);

               }
               catch(Exception e)
               {
                   System.out.println("file not opened");
                }
            }
然后将其放入另一个线程:

public void run()
{
    boolean running=true;
    while(running)
    {
        // System.out.println("Img sender running");
        if(imageready.getFlag())
        { System.out.println("trying to send img");
            try
            {
                  OutputStream outputStream = img_s.getOutputStream();
                  ImageIO.write(image.getImg(), "jpg", outputStream);

                  System.out.println("Send image"+System.currentTimeMillis());
                  outputStream.flush();
                  outputStream.close();
                  imageready.setFlag(false);

            }
            catch(Exception e)
            {
                System.out.println("image client send failed");
                imageready.setFlag(false);
            }
        }
     }
 }
我期望的是,在选择文件后,imageready应设置为true,然后获得该标志的线程执行块内的语句:

if(imageready.getFlag()){...send image...}
但即使imageready设置为true,它也不会进入块中

正如您可能注意到的,在if块之前,有一条语句被注释掉了:

// System.out.println("Img sender running");
如果我不注释掉它,If块中的语句将被执行。把其他不相关的语句,如sleep(100)也会产生同样的效果。如果我在If(imageready.getflag())处放置一个断点,然后一步一步地执行它,它也会进入块中

如果我将getter和setter设置为同步,这些问题就不会发生。
看起来这是关于Tread安全类的,但我不明白为什么它很重要,即使我只是使用getter和setter。

您的get访问器很可能是内联的,因此它实际上只是一个字段读取,并且运行时可以优化掉出现在循环中的简单字段读取,从而使值有效地只读取一次

您可以通过读取
volatile
值来避免这种情况,或者如您所注意到的,在写入和读取标志时,使用
synchronized
强制设置内存障碍

在您的情况下,我只需要使用
AtomicBoolean
来代替
BoolFlag


另一方面,我会避免在第二个线程上忙着旋转“image ready”标志。考虑使用一个等待通知机制,例如,<代码> CurtDutLabCH < /C> >计数>>1 /代码> .< /P> < P>是的,这是由于线程通信,而您所要实现的是:

您的代码有几个问题:

1) 写入映像文件的线程类在
getFlag()
方法中没有被阻止,因此while循环可能会在保持线程活动的情况下大量运行。相反,在
getFlag()
中阻塞线程,并使用
wait()
notifyAll()
方法进行有效的线程通信


。在您的情况下,您需要做类似的事情来管理线程。

同步没有提供编写线程安全类的便利。在多线程环境中,如果一个对象在多个线程之间共享,则不存在任何可能影响程序正确性的问题,如数据争用、脏读、过时值

为了优化代码,java将变量数据保存在内存缓冲区中,以便更快地访问。由于其他线程对该变量所做的更改可能不会立即反映出来,这就是为什么其他线程读取该变量以前的值,因此无法在不久的将来读取更新后的值


您可以将变量定义为volatile。Volatile请确保线程将获得Java内存模型提交的变量最近更新的值。

但是if(imageready.getFlag())将保持运行,并保持检查imageready是否更改为true,因为它在线程的while(true)循环中。那么为什么它不能得到imageready的更新值呢?谢谢。正如我所说,每个线程都有自己的堆栈区域和存储在寄存器中的值,所以一旦捕获到它,它可能无法获得更新的值……在生产者-消费者问题中,生产者和消费者会修改同一个对象。但我的情况有点不同:一个线程正在修改imageready的值,而另一个线程只是在不更改其值的情况下获取它。