Подтвердить что ты не робот

Можно ли использовать instanceof при передаче объектов между Threads?

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

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

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

(Я хочу, чтобы статья, связанная в начале обсуждения, все еще была доступна, но это не похоже на нее.)

4b9b3361

Ответ 1

Это не имеет ничего общего с потоками, только с загрузчиками классов. Такое же определение класса, когда оно загружается разными загрузчиками классов, рассматривается JVM как два разных класса. Итак, instanceof или отбрасывает между двумя ошибками.

Итак, чтобы ответить на ваш первоначальный вопрос: передача объектов между потоками, загружаемыми одним и тем же загрузчиком классов, безопасна и instanceof et al. отлично работает.

Вот статья о проблемах загрузки классов.

См. также этот ранее мой ответ, чтобы узнать, какие загрузчики классов находятся в игре.

Обновить комментарий Romain

Вот какой код для проверки поведения 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: [email protected]
foo2: [email protected]
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

Итак, все кажется последовательным: -)

Ответ 2

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