拿上面的例子来说明,在多个线程之间共享了count类的一个实例,这个对象是被创建在主内存(堆内存)中,每个线程都有自己的工作内存(线程栈),工作内存存储了主内存count对象的一个副本,当线程操作count对象时,首先从主内存复制count对象到工作内存中,然后执行代码count.count(),改变了num值,最后用工作内存中的count刷新主内存的 count。当把变量声明为volatile类型后,编译与运行时都会注意到这个变量是共享的,因此不会将该变量上的操作与其他内存操作一起重排序。java程序员都知道如果一个对象没有任何引用了,那么这个对象在gc的时候就被回收了,这就是我们常见的强引用,这种方式过于简单直接,对于一些特殊的java对象,如缓存数据在内存紧张时自动释放掉空间防止oom、直接内存对象回收之前需自动释放掉其占用的堆外内存,当socket对象被回收之前关闭连接,当文件流对象被回收之前自动关闭打开的文件等操作,为了实现这些特殊需求,java还引入了除了强引以外的引用类型来辅助对象回收操作 或 控制对象的生存周期。
虽然可以让sta线程直接调用对象(而不用像前述的挂起等待另一个线程来调用对象),但这是必须的,因为可能会有回调问题,比如这个mta线程又反过来回调外界线程中的组件对象(假设客户本身也是一个组件对象,这正是连接点技术),如果异步回调将可能发生错误。上述代码与前面不同的是我们同时创建了两个新实例accountingsyncbad,然后启动两个不同的线程对共享变量i进行操作,但很遗憾操作结果是1452317而不是期望结果2000000,因为上述代码犯了严重的错误,虽然我们使用synchronized修饰了increase方法,但却new了两个不同的实例对象,这也就意味着存在着两个不同的实例对象锁,因此t1和t2都会进入各自的对象锁,也就是说t1和t2线程使用的是不同的锁,因此线程安全是无法保证的。当a线程调用anyobject对象加入synchronized关健字的x方法时,a线程就获得了x方法所在对象的锁,所以其他线程必须等a线程执行完毕才可以调用x方法,而b线程如果调用声明了synchronized关键字的非x方法时,必须等a线程将x方法执行完,也就是释放对象锁后才可以调用。

当缓存对象不存在的时候会调用newReflectionData,注意到该方法实际上用了一个死循环+CAS操作,由于reflectionData变量是volatile内存可见的,死循环+cas+volatile是保证线程安全的常用手法(可以参见我前面concurrent包的博客),Atomic.casReflectionData保证线程安全的创建了缓存对象。值得注意的是新创建的内存内部只有成员变量而没有成员方法和构造方法供反射获取!!!
ReflectionData<T> rd = reflectionData();
private volatile transient SoftReference<ReflectionData<T>> reflectionData;
private ReflectionData<T> reflectionData() {
SoftReference<ReflectionData<T>> reflectionData = this.reflectionData;
int classRedefinedCount = this.classRedefinedCount;
ReflectionData<T> rd;
if (useCaches &&
reflectionData != null &&
(rd = reflectionData.get()) != null &&
rd.redefinedCount == classRedefinedCount) {
return rd;
}
return newReflectionData(reflectionData, classRedefinedCount);
}
private ReflectionData<T> newReflectionData(SoftReference<ReflectionData<T>> oldReflectionData,
int classRedefinedCount) {
if (!useCaches) return null;
while (true) {
ReflectionData<T> rd = new ReflectionData<>(classRedefinedCount);
if (Atomic.casReflectionData(this, oldReflectionData, new SoftReference<>(rd))) {
return rd;
}
oldReflectionData = this.reflectionData;
classRedefinedCount = this.classRedefinedCount;
if (oldReflectionData != null &&
(rd = oldReflectionData.get()) != null &&
rd.redefinedCount == classRedefinedCount) {
return rd;
}
}
}
再次,缓存对象创建完成之后成员方法类型和构造方法类型是什么时候加到缓存里面去的呢?这里我们以Method成员方法为例,在某个线程调用getDeclaredMethod方法获取/创建了缓存对象之后,接着首先会从缓存中获取该方法,如果获取不到才会调用Reflection.filterMethods方法从VM虚拟机中获取,然后如果有缓存的话更新缓存。
private Method[] privateGetDeclaredMethods(boolean publicOnly) {
checkInitted();
Method[] res;
ReflectionData<T> rd = reflectionData();
if (rd != null) {
res = publicOnly ? rd.declaredPublicMethods : rd.declaredMethods;
if (res != null) return res;
}
// 没有缓存的条件下从虚拟机中获取
res = Reflection.filterMethods(this, getDeclaredMethods0(publicOnly));
if (rd != null) {
if (publicOnly) {
rd.declaredPublicMethods = res;
} else {
rd.declaredMethods = res;
}
}
return res;
}
线程使用mutex.waitone()方法等待c# mutex对象被释放,如果它等待的c# mutex对象被释放了,它就自动拥有这个对象,直到它调用mutex.releasemutex()方法释放这个对象,而在此期间,其他想要获取这个c# mutex对象的线程都只有等待。而线程与c# mutex对象的关系也正是如此,线程使用mutex.waitone()方法等待c# mutex对象被释放,如果它等待的c# mutex对象被释放了,它就自动拥有这个对象,直到它调用mutex.releasemutex()方法释放这个对象,而在此期间,其他想要获取这个c# mutex对象的线程都只有等待。而线程与c# mutex对象的关系也正是如此,线程使用mutex.waitone()方法等待c# mutex对象被释放,如果它等待的c# mutex对象被释放了,或者它没有被任何对象有用,它就自动拥有这个对象,直到它调用mutex.releasemutex()方法释放这个对象,而在此期间,其他想要获取这个c# mutex对象的线程都只有等待。
private static Method searchMethods(Method[] methods,
String name,
Class<?>[] parameterTypes)
{
Method res = null;
String internedName = name.intern();
for (int i = 0; i < methods.length; i++) {
Method m = methods[i];
if (m.getName() == internedName
&& arrayContentsEq(parameterTypes, m.getParameterTypes())
&& (res == null
|| res.getReturnType().isAssignableFrom(m.getReturnType())))
res = m;
}
return (res == null ? res : getReflectionFactory().copyMethod(res));
}
Method copy() {
if (this.root != null)
throw new IllegalArgumentException("Can not copy a non-root Method");
Method res = new Method(clazz, name, parameterTypes, returnType,
exceptionTypes, modifiers, slot, signature,
annotations, parameterAnnotations, annotationDefault);
res.root = this;
// Might as well eagerly propagate this if already present
res.methodAccessor = methodAccessor;
return res;
}
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-111385-2.html
现在是剩女多好吧
少读书