Можно ли использовать instanceof при передаче объектов между потоками? - PullRequest
14 голосов
/ 12 июня 2010

Я столкнулся с проблемой, когда instanceof работает, а затем - нет.Трудно вдаваться в детали, но я думаю, что это может быть проблемой:

Чтение этого: http://www.theserverside.com/news/thread.tss?thread_id=40229 (поиск Thread.currentThread), кажется, что, даже если два объектатот же класс, если вы передадите их между потоками с разными загрузчиками классов, instanceof (и isAssignableFrom) все равно может потерпеть неудачу.

Это, безусловно, объяснило бы поведение, которое я имею, но мне было интересно, если кто-нибудь сможет это проверить?

(Хотелось бы, чтобы статья, на которую ссылались в начале обсуждения, все еще была доступна, но не похоже, что она есть.)

Ответы [ 2 ]

29 голосов
/ 12 июня 2010

Это не имеет ничего общего с потоками, только с загрузчиками классов. Одно и то же определение класса, когда оно загружается разными загрузчиками классов, 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));

И вывод (в Eclipse, Java5):

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

Так что все вроде бы согласованно: -)

1 голос
/ 12 июня 2010

Проблема, как говорит Петер Тёрёк, с загрузчиками классов. Кстати, это также причина для JNDI, который позволяет создавать общие объекты одним центральным загрузчиком классов (это означает также, что нужные вам классы должны находиться в пути к классам одного центрального загрузчика классов, предоставляя все виды удовольствия при нужно больше, чем просто строки).

...