Java 实例变量和线程

Java 实例变量和线程,java,multithreading,volatile,Java,Multithreading,Volatile,我有一个像下面这样的类,我想知道,这是线程安全的还是主线程和加载程序线程可能有自己的mCache副本,因此get(..)方法无法从缓存中检索添加到加载程序线程中的任何内容?是否需要将此标记为volatile 谢谢 public class StackExample { private final ConcurrentHashMap<String, SoftReference<Bitmap>> mCache = new ConcurrentHashMap<St

我有一个像下面这样的类,我想知道,这是线程安全的还是主线程和
加载程序
线程可能有自己的
mCache
副本,因此get(..)方法无法从缓存中检索添加到加载程序线程中的任何内容?是否需要将此
标记为volatile

谢谢

public class StackExample
{
    private final ConcurrentHashMap<String, SoftReference<Bitmap>> mCache = new ConcurrentHashMap<String, SoftReference<Bitmap>>();

    private addToCache(String key, Bitmap bitmap)
    {
        mCache.put(key, bitmap);
    }

    private Bitmap getBitmap(String key)
    {
        if(mCache.contains(key))
        {
            return mCache.get(key);
        }
        else
        {
            //add to loading queue
        }
    }

    private class Loader extends Thread
    {
        @Override
        public void run() 
        {
            ...//check loading queue and load some images here
            mCache.put(keyString, new SoftReference<Bitmap>(loadedBitmap));
        }
    }
}
公共类堆栈示例
{
私有最终ConcurrentHashMap mCache=新ConcurrentHashMap();
私有addToCache(字符串键、位图)
{
输入(键,位图);
}
私有位图getBitmap(字符串键)
{
if(mCache.contains(键))
{
返回mCache.get(key);
}
其他的
{
//添加到加载队列
}
}
私有类加载器扩展线程
{
@凌驾
公开募捐
{
…//检查加载队列并在此处加载一些图像
put(键串,新的软引用(loadedBitmap));
}
}
}


该变量是final,因此在构造函数(本例为空)返回之前,所有线程都可以看到它。

该变量是final,因此在构造函数(本例为空)返回之前,所有线程都可以看到它。

volatile
意味着每个线程都不会保留字段值的缓存。如果您能够写入mCache字段,那么如果您希望确保另一个线程在另一个线程设置字段后立即读取该字段时获得新值,则可以将其声明为volatile。

volatile
意味着每个线程都不会保留该字段值的缓存。如果您能够写入mCache字段,那么如果您希望确保另一个线程在另一个线程设置字段后立即读取该字段时获得新值,那么您会将其声明为volatile。

它是可变的,这不重要吗?最后一个字段永远不会受到持有自己副本的线程的影响吗?@Dori:你认为会复制什么
ConcurrentHashMap
是可变的,但设计用于多线程而无需锁定。对不起,我可能有一个错误的印象,即所有变量都可以由使用它们的每个线程作为本地副本保存,导致一个线程可能无法查看另一个线程对该变量所做的更改。在某些情况下,volatile关键字可以防止这种情况,但不会停止交错操作。我还认为同步停止了交错操作,但我不确定它对变量的本地复制/缓存有什么影响-当同步块启动/退出时,变量是否被刷新/推送到主存?@Dori:但变量的值只是引用,而不是对象。这个变量是最终的,所以这个值不能改变。有关更多详细信息,请参阅Java语言规范的内存模型部分。好的,谢谢jon,我显然需要阅读一篇文档!我认为,如果我使用一个普通的hashMap,我可能会在这里遇到问题?它是可变的,这不重要吗?最后一个字段永远不会受到持有自己副本的线程的影响吗?@Dori:你认为会复制什么
ConcurrentHashMap
是可变的,但设计用于多线程而无需锁定。对不起,我可能有一个错误的印象,即所有变量都可以由使用它们的每个线程作为本地副本保存,导致一个线程可能无法查看另一个线程对该变量所做的更改。在某些情况下,volatile关键字可以防止这种情况,但不会停止交错操作。我还认为同步停止了交错操作,但我不确定它对变量的本地复制/缓存有什么影响-当同步块启动/退出时,变量是否被刷新/推送到主存?@Dori:但变量的值只是引用,而不是对象。这个变量是最终的,所以这个值不能改变。有关更多详细信息,请参阅Java语言规范的内存模型部分。好的,谢谢jon,我显然需要阅读一篇文档!我认为如果我使用一个普通的hashMap,我可能会在这里遇到问题?你只有一个唯一的mCache对所有线程可见,但是你的代码仍然没有正确同步。您可以为同一个密钥输入两次(或更多)代码的//添加到加载队列部分,尽管从您的示例中不完全清楚从何处调用getBitmap(它显然是私有的!).btw+1回答你的问题,为那些对Jon Skeet的一句话答案投了高票而没有对你的好问题投高票的人感到羞耻。谢谢!是的,这只是一个简单的例子,我确实知道你对get方法的意思:)你只有一个唯一的mCache对所有线程可见,但是你的代码仍然没有正确同步。您可以为同一个密钥输入两次(或更多)代码的//添加到加载队列部分,尽管从您的示例中不完全清楚从何处调用getBitmap(它显然是私有的!).btw+1回答你的问题,为那些对Jon Skeet的一句话答案投了高票而没有对你的好问题投高票的人感到羞耻。谢谢!是的,这里只是一个简单的例子,我确实知道你关于get方法的意思:)从上面我认为这不适合这种情况,因为该字段只是一个引用,并且是最终的。当它不能从上面更改时,没有理由声明它是易变的,我认为这不适合这种情况,因为该字段只是一个引用,并且是最终的。当它无法更改时,没有理由将其声明为易失性