1.前言
优化Application时,由于上报uv和pv的操作初始需要读取配置和加载so库很多io操作,相对非常耗时,所以参考SharedPerfencesImpl的实现做了延迟加载,如果发现需要使用但是为初始完成会让调用线程wait.所以初始化结束时需要调用notifyall.
2. 问题
代码示例
public class Demo{
public void init(){
new Thread(){
public void run() {
synchronized (Demo.this) {
//io操作
//初始化赋值操作
notifyAll();
}
}
}
}
在上面的同步块中直接调用notifyAll();这里会产生错误:
IllegalMonitorStateException: object not locked by thread before notify
当时一直不明白为何会产生这个错误,后面这么修改:
synchronized(this){
notifyAll();
}
当时没有报错,而且用户数据也上报成功,也就没有细节去分析.现在回头来看,突然发现这里的调用并不是正确的.正确的调用应该是
Demo.this.notifyAll();
或
public class Demo{
public void init(){
new Thread(){
public void run() {
synchronized (Demo.this) {
loadInit();
}
}
}
private void loadInit(){
//io操作
//初始化赋值操作
notifyAll();
}
}
3.原因
notifyall需要在同步块中,所以需要去获取当前对象的锁,而第一次直接调用是表示Thread.this.notifyAll();但是并没有去获取线程的锁.而加了synchronized(this){}不会报错了,是因为获取了Thread对象的锁,但是没有线程因为Thread对象wait.所以不是我们需要的效果.而后面的两种解决方案的实质是一样的.都是调用Demo.this对象的notifyall,但是后民使用方法替代,而没有使用Demo.this.notifyall的原因是,线程内部类隐式持有外部引用,而loadInit方法是外部Demo的方法,所以调用的时候是Demo.this.loadInit();所以执行notifyall的操作对象是Demo.this,而不是Thread.