Инициализация двух потоков с одним и тем же экземпляром работающего - PullRequest
18 голосов
/ 05 марта 2012

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

public static void main(String[] args)throws Exception {
   H h = new H();
   H h2 = new H();
   Thread j = new Thread(h);
   j.setName("11");

   Thread jj = new Thread(h);//instead of new H()
   jj.setName("22");
   j.start();
   jj.start();
}

class H implements Runnable {
    public void run() {
        while(true) {
           System.out.println(Thread.currentThread().getName());
        }
    }
}

Ответы [ 4 ]

18 голосов
/ 05 марта 2012

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

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

9 голосов
/ 05 марта 2012

Поскольку H не имеет состояния экземпляра, использование нескольких экземпляров не имеет значения. Вам нужно позаботиться, когда экземпляры Runnable начнут сохранять состояние.

public class Main implements Runnable {
    volatile int i;
        public void run() {
        for (i = 0; i < 100; i++) {
            System.out.println(i);
        }
    }

    public static void main(String[] args) {
        Main a = new Main();
        Thread t1 = new Thread(a);
        Thread t2 = new Thread(a);
        t1.start();
        t2.start();
    }        
}

Что получает напечатано ? Когда вам нужно разделить состояние между потоками, рекомендуется использовать классы в java.util.concurrent. Они были написаны в основном экспертом по многопоточности ( Даг Ли , автор Параллельное программирование на Java ) и протестированы многими людьми. Сэкономь себе душевную боль. :)

7 голосов
/ 05 марта 2012

Плохо ли программировать инициализацию двух потоков с одним и тем же экземпляром работоспособного объекта?

Не специально.Однако, если у экземпляра Runnable есть поля экземпляра, вам необходимо убедиться, что весь доступ к полям потока правильно синхронизирован, и это усложнит код.

Какая разница для инициализации с отдельными экземплярами работоспособного объекта и имеет ли какое-либо отношение производительность к общему расположению памяти для одного и того же экземпляра работоспособного объекта?

Память, сохраненная при совместном использованииRunnable экземпляр между несколькими потоками незначителен ... если только Runnable не содержит значительного количества данных экземпляра.(И если это произойдет, есть вероятность, что это сделает экземпляр не доступным для совместного использования.)


Ваш класс H является примером, в котором совместное использование экземпляров безопасно, но бессмысленно, поскольку экономия памятинезначительный.(Объект Runnable без полей экземпляра занимает примерно от 8 до 16 байт, в зависимости от платформы.)

0 голосов
/ 17 мая 2017

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

public class SynchronizedInstanceMethod implements Runnable{

private int counter;

public SynchronizedInstanceMethod(int counterValue){
    this.counter = counterValue;
}

private synchronized void displayMessage(){
    System.out.println(" Display Message ");
}

private void modifyCounter(){
    this.counter++;
    System.out.println("Value -- "+ this.counter);
}

@Override
public void run() {
    this.displayMessage();
    this.modifyCounter();
}

public static void main(String[] args) {
    SynchronizedInstanceMethod instance = new SynchronizedInstanceMethod(5);
    new Thread(instance).start();
    new Thread(instance).start();
}
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...