我有一个类,它必须是一个单例:同步静态方法不能在android中工作?
private static StationsFile instance;
private Context ctx;
protected StationsFile(Context ctx){
this.ctx = ctx;
load();
}
public static synchronized StationsFile getInstance(Context ctx){
if(instance == null){
Log.d("StationsFile", "set instance " + StationsFile.class.hashCode());
instance = new StationsFile(ctx);
Log.d("StationsFile", "instance set " + instance.hashCode());
}
return instance;
}
protected static StationsFile getInstance(){
return getInstance(null);
}
private void load(){
if(externalStorageIsReadable()){
// Loads from sd file
}else{
loadDefaults();
}
}
private void loadDefaults(){
if(this.ctx != null){
// Load from raw file in raws folder (I need a context to access Resources)
}else{
// Hardcoded default here
}
}
现在,这种方法是同步的,它是静态的,它应该是一次只调用一次。当我在我的设备(Android 4.4)中运行它时,没有任何问题(在我的日志中,我获得了“set instance - instance set”),但是当我在Android中第一次(并且仅在安装后第一次) 2.2虚拟设备或每次在Android 4.4虚拟设备中,我都会在我的日志“set instance - set instance - instance set - instance set”中出现,并因此导致崩溃。
所以它看起来像当启动“慢”崩溃。对我来说,它看起来像synchronized关键字不起作用。
,此方法被从2个不同的线程在应用程序的一开始叫。一个线程从互联网上下载并解析文件,所以它被更新,而另一个线程(主线程)只是读取它。 (我不需要一个在另一个之前发生,因为如果它没有从互联网加载它只是从内部存储器中读取它)。
这是来自虚拟设备的错误吗?我的意思是,因为它是同步的(并且据我所知),所以不能同时调用两次。我怎样才能解决这个问题?
编辑:refractoring我的课,并使其遵循Singleton模式神奇地修复它。在我有公共静态方法访问getInstance之前,所以“我不必把getInstance放到任何地方我都想调用这个类”。尽管如此,我要回滚我的代码以找出问题所在(我正在使用git回购)。
EDIT2:使用哈希码,我得到的日志: “设置实例1139286928 - 设置实例1139286928 - 例如设置1139224312 - 例如设置1139287568”
EDIT3:发现的bug。问题是,当他在Resourcers文件夹中加载文件时,loadDefaults方法,他再次使用getInstance()分析该文件(调用我所拥有的loadFromString方法)。我认为这是两个不同的主题,但它是同一个主题,因此为什么同步对它没有任何影响。
没有人能阻止调度程序上下文切换你的第一个线程,并让运行第二个,之前的getInstance()完成之后才能执行。 – Blackbelt
你确定你没有参与某种原因两个不同的类加载器?在这种情况下, ,你就会有两个独立的Class对象这将是值得记录身边的东西 - 比如'Log.d(“StationsFile.class哈希:” + StationsFile.class.hashCode()); –
@JonSkeet真的野趣,但它的不是这样的。我测试了一下,我得到了在这两个调用相同的hashCode(1139286840)。 – olivarra1