1

Как сделать несколько нитей в Java ручка, работающая с ссылка на один объект?Сделайте несколько потоков Используя один и тот же объект в java, сделайте его копию?

Выполняют ли они копию объекта, а затем используют его или используют один и тот же?

Любое техническое объяснение приветствуется.

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

Будет ли последняя информация перезаписывать предыдущую в объекте?

+0

Объекты не копируются автоматически. Вы должны следить за тем, чтобы несколько потоков не изменяли один и тот же объект одновременно. См. Это [учебник о параллелизме] (например, http://docs.oracle.com/javase/tutorial/essential/concurrency/). – Jesper

ответ

1

Выполняют ли они копию объекта, а затем используют его или используют один и тот же?

Оба, фактически.

Современные компьютеры спроектированы в соответствии с Симметричная многопроцессорная архитектура (SMP), в которой несколько процессоров конкурируют за доступ к общей системе памяти. Чтобы уменьшить количество соревнований, каждый процессор имеет свой собственный кэш - небольшое количество высокоскоростной памяти - там, где он хранит рабочие копии данных, которые принадлежат к основной памяти.

Кэширование происходит в аппаратном обеспечении, а аппаратное обеспечение ничего не знает о объектах Java, поэтому это происходит на байтовом уровне, а не на уровне объекта за объектом.

На уровне языка имеется только одна копия объекта, но на аппаратном уровне разные потоки, работающие на разных процессорах, могут иметь свои собственные копии частей объекта.


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

Java имеет строгие правила о том, когда и как различные потоки должны координировать свои тайники. Чтобы узнать больше об этих правилах, Google для «Java» и «модель памяти», или «видимость памяти», или «произойдет раньше».


Если вы не хотите, чтобы прочитать все окровавленные детали, секрет в разумном использовании synchronized блоков и synchronized методов. Если вы хотите запомнить только одно правило, помните об этом: независимо от того, какой поток используется для общих объектов до того, как он покинет блок synchronized, гарантируется, что он станет видимым для других потоков после того, как эти потоки войдут в блок, который равен , с той же блокировкой.

+0

Я хочу знать сложную техническую информацию, если вы можете сделать giude мне книги или ресурсы. –

+0

@AnoopMoorthy Google для «java» и «model memory», или «java» и «видимость памяти», или «java» и «бывает раньше»; или прочитайте раздел 17.4 Спецификации языка Java8 https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.4; или прочитайте «Java Concurrency in Practice» https://www.amazon.com/Java-Concurrency-Practice-Brian-Goetz/dp/0321349601 –

+0

ok, great.i будет читать –

0

ли они сделать копию объекта, а затем использовать его, или они используют один и тот же один

копия не делается. Темы будут использовать один и тот же объект.

+0

Я не могу понять это в контексте, что если потоки передают некоторые данные объекту и переходят в спящий режим, в то время как один спит, другой поток использует один и тот же объект, передает ему данные и переходит в режим сна. Будут ли последние данные перезаписаны в объекте? –

+0

оба потока будут записывать в ту же область памяти, поэтому да, она будет перезаписана. – Azodious

1

Составляют ли они копию объекта, а затем используют его?

Нет. Все они используют один и тот же объект. И поэтому правильная синхронизация настолько важна для общих изменяемых объектов.

Любое техническое объяснение приветствуется.

Это не отличается от того, как объекты передаются в однопоточных контекстах. Ссылки на объекты передаются по значению. Нет копирования объектов. Только копирование ссылок.

0

Вы можете посмотреть модель памяти Java. Вы видите, что все объекты хранятся в Heap-памяти, которая совместно используется для всего приложения. Каждый поток разделяет одно и то же пространство кучи, но также имеет собственную стек памяти, где они хранят свою ссылку на объекты. Поэтому, если один поток работает на объекте, он имеет свою ссылку на этот объект, но эта ссылка указывает на объект в куче пространства, который будет видеть каждый поток. Поэтому, чтобы ответить на ваш вопрос, если второй поток будет что-то делать с объектом, а затем переспать или даже умереть, предыдущий поток при пробуждении увидит эти изменения, потому что его ссылка указывает на тот же объект.

Я нашел интересный образ, который может помочь вам понять:

http://tutorials.jenkov.com/java-concurrency/java-memory-model.html

изображение из: http://tutorials.jenkov.com/java-concurrency/java-memory-model.html

0

Из личного примера. Я делал космические захватчики для личного роста, и он использовал несколько Thread с. Один Thread обработал рендеринг и другую обработанную логику игры. Это до того, как я убедился в параллельности и как правильно реализовать его на Java.

Anyways, у меня был ArrayList<Laser>, который держал все Laser s в системе на любом данном фрейме в игре (или так я думал). Из-за природы космических захватчиков List был чрезвычайно динамичным.Он постоянно добавлялся в качестве новых Laser s, порожденных и удаленных, поскольку они либо ушли с карты, либо столкнулись с сущностью.

Это работало хорошо и хорошо, за исключением случаев, когда я так часто получал ConcurrentModificationException. Мне потребовалось много времени, чтобы точно выяснить, что происходит. Оказывается, что рендеринг Thread был в редких случаях пойманным итерированием через List<Laser> одновременно с тем, что игровая логика Thread либо добавляла новые Laser s, либо удаляла их.

Это связано с тем, что когда Thread 1 получает указатель на место пятна в памяти, оно почти похоже на то, что оно «работает» на этом блоке памяти. Thread 2 приходит и хватает, что тот же указатель не знает, что объект уже находится на «операционном столе», измененном Thread 1, и он пытается сделать то, что он намеревался, только чтобы найти то, что Thread 2 думал, что это действительно известно об объекте не удалось из-за изменений Thread. Это то, что заканчивается броском ConcurrentModificationException.

Это можно решить несколькими различными способами. Я думаю, что самый эффективный и безопасный способ решить это сейчас - это API-интерфейс Java 8 Stream (если все сделано правильно, оно обеспечит true параллелизм), или вы можете использовать блоки (я думаю, что они появились на Java 5). С блоками synchronized текущий Thread, который смотрит на объект, по существу заблокирует его, не позволяя другим Thread s даже наблюдать за объектом. Как только Thread будет выполнен, он освободит объект для следующего Thread для его работы.

Вот два примера того, как использовать synchronized:

public synchronized void xamp1(List<Laser> lasers){ 
    for(Laser l:lasers){ 
     //code to observe or modify 
    } 
} 


public void xamp2(List<Laser> lasers){ 
    synchronized(lasers){ 
     for(Laser l:lasers){ 
      //code to observe or modify 
     } 
    } 
} 
0

Нить может делать копии, если:

  1. вы пишете код на эту
  2. входящих объекты могут фактически быть " (клонировано)

Другими словами: по умолчанию используется то, что есть no неявное копирование вообще. Не с 1 нитью; не с N нитями.

Если вам нужна такая функциональность, вы сами реализуете ее.

Для простых ситуаций, например, для передачи списка; что можно сделать довольно легко (для уровня топ):

List<Whatever> duplicatedList = new ArrayList<>(existingList); 

, чтобы затем дать duplicatedList другим потокам. Но, конечно же: это создает только несколько списков - записи в списке все еще ссылаются на одни и те же объекты!

Глубокое клонирование - это понятие, которое трудно сделать в java и поэтому редко используется на практике.

Смежные вопросы