Я хочу знать, почему этот результат не 1000000 - PullRequest
1 голос
/ 05 июня 2019

Я использовал пул потоков для создания 100 потоков, добавил деньги и использовал синхронизацию, но результат не достиг 1000000.

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadPool {

    public static void main(String[] args) {
        ExecutorService pool = Executors.newFixedThreadPool(100);
        for(int i=0;i<100;i++) {
            Thread t=new MyThread();
            pool.execute(t);
        }
        pool.shutdown();
    }
}

class MyThread extends Thread{

    private static int money=0;

    @Override
    public void run() {
        addMoney();
    }

    public synchronized void addMoney() {
        for(int i=0;i<10000;i++)
            money+=1;
        System.out.println(money);
    }
}

Ответы [ 2 ]

1 голос
/ 05 июня 2019

Ключевое слово synchronized, добавленное вами к методу addMoney, использует this в качестве встроенной блокировки. Поскольку this указывает на каждый из экземпляров потока, и каждый поток вызывает этот метод только один раз, это не имеет никакого эффекта.

Чтобы синхронизировать доступ между потоками, вы можете явно указать экземпляр глобальной блокировки, например, ThreadPool класс:

public void addMoney() {
    synchronized(ThreadPool.class) {
        for(int i=0;i<10000;i++)
            money+=1;
        System.out.println(money);
    }
}

Вы можете добиться почти того же в вашем случае, объявив метод addMoney как static. В этом случае встроенной блокировкой будет класс MyThread:

public static synchronized void addMoney() {
    for(int i=0;i<10000;i++)
        money+=1;
    System.out.println(money);
}

Более подробную информацию вы можете найти в документации по Java https://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html

0 голосов
/ 05 июня 2019

Проблема заключается в том, что каждая из ваших задач синхронизируется с другим объектом при доступе и обновлении общей статической переменной. Это означает, что между рабочими потоками нет взаимного исключения. Это означает, что значение, рассчитанное вашим приложением, может быть непредсказуемым и / или зависящим от платформы. (Если вам не повезет ...)

Один из подходов к исправлению состоит в том, чтобы изменить addMoney на static synchronized метод. Это приведет к синхронизации потоков на объекте MyThread.class. Однако, если вы сделаете это, вы обнаружите, что ваше приложение эффективно однопоточное ... потому что только один из ваших MyThread экземпляров сможет одновременно выполнить свой метод addMoney.

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


Вы не должны расширять Thread. Ваш MyThread класс должен быть заменен классом, который реализует Runnable. Здесь вы используете Thread объект, как если бы он был просто Runnable. Это плохая идея. ExecutorService, который вы используете, позаботится о создании потока. Вы должны кормить его "задачами", а не "потоками".

...