Java 在线程之间传递对象时是否可以使用instanceof?

Java 在线程之间传递对象时是否可以使用instanceof?,java,multithreading,classloader,instanceof,Java,Multithreading,Classloader,Instanceof,我遇到了一个问题,instanceof可以工作,但它却不能。深入了解细节是困难的,但我认为这可能是问题所在: 阅读本文:(搜索Thread.currentThread),这似乎意味着,即使这两个对象是同一个类,如果使用不同的类装入器在线程之间传递它们,instanceof(和isAssignableFrom)可能仍然会失败 这当然可以解释我的行为,但我想知道是否有人能证实这一点 (我希望在讨论开始时链接的文章仍然可用,但看起来不是这样。)这与线程无关,只与类加载器有关。当同一个类定义由不同的类加

我遇到了一个问题,instanceof可以工作,但它却不能。深入了解细节是困难的,但我认为这可能是问题所在:

阅读本文:(搜索Thread.currentThread),这似乎意味着,即使这两个对象是同一个类,如果使用不同的类装入器在线程之间传递它们,instanceof(和isAssignableFrom)可能仍然会失败

这当然可以解释我的行为,但我想知道是否有人能证实这一点


(我希望在讨论开始时链接的文章仍然可用,但看起来不是这样。)

这与线程无关,只与类加载器有关。当同一个类定义由不同的类加载器加载时,JVM将其视为两个不同的类。因此,
instanceof
或两者之间的强制转换失败

因此,要回答您最初的问题:在由同一类加载器加载的线程之间传递对象是安全的,
instanceof
等工作正常

这是一个例子

另请参阅,以了解验证游戏中有哪些类加载器的方法

罗曼评论的更新 以下是一些测试
instanceof
行为的代码,其中包括:

URL[] urls = new URL[] {new File("build/classes/").toURL()};
ClassLoader loader1 = new URLClassLoader(urls, null);
ClassLoader loader2 = new URLClassLoader(urls, null);
Class<?> c1 = loader1.loadClass("net.torokpeter.Foo");
Class<?> c2 = loader2.loadClass("net.torokpeter.Foo");
Object foo1 = c1.newInstance();
Object foo2 = c2.newInstance();

System.out.println("c1.toString(): " + c1);
System.out.println("c2.toString(): " + c2);
System.out.println("c1.equals(c2): " + c1.equals(c2));
System.out.println("c1 == c2: " + (c1 == c2));
System.out.println("foo1: " + foo1);
System.out.println("foo2: " + foo2);
System.out.println("foo1 instanceof Foo: " + (foo1 instanceof Foo));
System.out.println("foo2 instanceof Foo: " + (foo2 instanceof Foo));
System.out.println("c1.isAssignableFrom(c1): " + c1.isAssignableFrom(c1));
System.out.println("c2.isAssignableFrom(c2): " + c2.isAssignableFrom(c2));
System.out.println("c1.isAssignableFrom(c2): " + c1.isAssignableFrom(c2));
System.out.println("c2.isAssignableFrom(c1): " + c2.isAssignableFrom(c1));
System.out.println("c1.isAssignableFrom(Foo.class): " + c1.isAssignableFrom(Foo.class));
System.out.println("c2.isAssignableFrom(Foo.class): " + c2.isAssignableFrom(Foo.class));
System.out.println("Foo.class.isAssignableFrom(c1): " + Foo.class.isAssignableFrom(c1));
System.out.println("Foo.class.isAssignableFrom(c2): " + Foo.class.isAssignableFrom(c2));

因此,一切似乎都是一致的:-)

问题在于,正如佩特·特若克所说,类加载器。顺便说一句,这也是JNDI允许由单个中心类加载器创建公共对象的原因(也就是说,您需要的类需要位于单个中心类加载器的类路径中,当您需要的不仅仅是字符串时,它提供了各种乐趣).

-1即使在不同的类加载器中,aClass instanceof aClassName仍将解析为true。如果用==来比较它们,那么它将不起作用。@Romain,我强烈怀疑,因为这意味着
instanceof
返回true,那么类强制转换将异常失败!这将是完全不合逻辑的,并且使得
的instanceof
完全不可靠。不过,还没有准备好具体的证据——如果你准备好了,请随意出示。@Peter I删除了-1。JVM将对象视为不同的类型,但instanceof仍将返回true。您是对的,这些类将抛出强制转换异常。两个类装入器可能共享一个父类装入器,这可能会装入一些类。这两个类加载器中的代码都是相同的,可能这就是造成混淆的原因。@starblue,正确。上面的类加载器是用
newurlclassloader(url,null)
创建的,它将它们的父类设置为
null
。但是,如果它们被创建为新的URLClassLoader(URL),它们共享同一个父类,然后它们加载的两个
Foo
类是一个相同的类。您如何在线程之间传递实例?如果做得不好,内存可见性会有微妙的问题。是的,我不是故意这么做的。事实上,我不确定线程是否真的是问题所在。我将向Java Logger处理程序传递一个参数,该处理程序采用Object[]形式的参数。我尝试将其转换回参数对象,但有时会失败,通常是在服务器上重新部署应用程序时。
c1.toString(): class net.torokpeter.Foo
c2.toString(): class net.torokpeter.Foo
c1.equals(c2): false
c1 == c2: false
foo1: net.torokpeter.Foo@360be0
foo2: net.torokpeter.Foo@45a877
foo1 instanceof Foo: false
foo2 instanceof Foo: false
c1.isAssignableFrom(c1): true
c2.isAssignableFrom(c2): true
c1.isAssignableFrom(c2): false
c2.isAssignableFrom(c1): false
c1.isAssignableFrom(Foo.class): false
c2.isAssignableFrom(Foo.class): false
Foo.class.isAssignableFrom(c1): false
Foo.class.isAssignableFrom(c2): false