Re: Brian Goetz и др. Java Concurrency in Practice
От: bolshik Россия http://denis-zhdanov.blogspot.com/
Дата: 09.08.06 08:51
Оценка:
Здравствуйте, Михаил Воронцов, Вы писали:

МВ>Книга будет полезна в первую очередь для Java разработчиков. Все повествование в книге идет вокруг джавовских примитивов синхронизации и классов, полезных при написании параллельных программ.


1. Скажите пожалуйста, после прочтения аннотации у меня сложилось впечатление, что книга ставит своей целью просто рассказать о классах из java.util.concurrent и его подпакетов. Так ли это?
2. Как вы считаете, на какой уровень расчитана эта книга? Вопрос возник потому, что в приведенном примере баг. Если представить ситуацию, когда вычисления объемны и длительны по времени, то возможно следующее -- клиент вызывает compute(), начинаются расчеты. После этого N других клиентов делают запрос на вычисление по тому же аргументу. Если расчеты длятся недопустимо долго, то данные уже могут стать не нужны первому клиенту. Он отменяет свой запрос. При этом мы с определенной вероятностью попадаем в бесконечный цикл.
Пример:

import java.util.concurrent.*;

/**
 * @author Denis Zhdanov
 */
public class CCC {

    private final ConcurrentHashMap<String, Future<Void>> cache = new ConcurrentHashMap<String, Future<Void>>();

    public static void main(String[] args) throws Exception {
        final CCC ccc = new CCC();

        Thread impatientThread = new Thread() {
            public void run() {
                System.out.println("Impatient client requested for data");
                try {
                    ccc.compute();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        System.out.println("Starting impatient client. ThreadId=" + System.identityHashCode(impatientThread));
        impatientThread.start();

        for (final int i : new int[] {1, 2}) {
            new Thread() {
                public void run() {
                    System.out.println("Starting client " + i + ". ThreadId=" + System.identityHashCode(this));
                    System.out.println("Client " + i + " requested for data");
                    try {
                        ccc.compute();
                        System.out.println("Client " + i + " received response");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }.start();
        }

        Thread.sleep(1000);
        System.out.println("Impatient client cancels request for data");
        impatientThread.interrupt();
    }

    public Void compute() throws InterruptedException {
        while (true) {
            Future<Void> f = cache.get("1");
            if (f == null) {
                Callable<Void> eval = new Callable<Void>() {
                    public Void call() throws InterruptedException {
                        System.out.println("Computation started");
                        Thread.sleep(3000);
                        System.out.println("Computation ended");
                        return null;
                    }
                };
                FutureTask<Void> ft = new FutureTask<Void>(eval);
                f = cache.putIfAbsent("1", ft);
                if (f == null) {
                    f = ft;
                    ft.run();
                }
            }
            try {
                return f.get();
            } catch (CancellationException e) {
                System.out.println("CancellationException, threadId=" + System.identityHashCode(Thread.currentThread()));
                cache.remove("1", f);
            } catch (ExecutionException e) {
                // cache.remove("1", f); (1)
                System.out.println("ExecutionException, threadId=" + System.identityHashCode(Thread.currentThread()));
            }
        }
    }
}

У меня примерно один раз из десяти случается shit. Shit выглядит так:

Starting impatient client. ThreadId=22837328
Impatient client requested for data
Computation started
Starting client 2. ThreadId=8451275
Client 2 requested for data
Starting client 1. ThreadId=3374351
Client 1 requested for data
Impatient client cancels request for data
ExecutionException, threadId=8451275
ExecutionException, threadId=22837328
ExecutionException, threadId=3374351
ExecutionException, threadId=8451275
ExecutionException, threadId=22837328
ExecutionException, threadId=3374351
ExecutionException, threadId=8451275
ExecutionException, threadId=3374351
ExecutionException, threadId=8451275
ExecutionException, threadId=22837328
etc


Лечится раскомментированием (1). После этого получаем

Starting impatient client. ThreadId=22837328
Impatient client requested for data
Starting client 2. ThreadId=8451275
Client 2 requested for data
Computation started
Starting client 1. ThreadId=3374351
Client 1 requested for data
Impatient client cancels request for data
ExecutionException, threadId=8451275
ExecutionException, threadId=3374351
ExecutionException, threadId=22837328
Computation started
Computation ended
Client 1 received response
Client 2 received response


Environment: WinXP Prof SP2, Sun jre 1.5.0_04
http://denis-zhdanov.blogspot.com
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.