В параллельности Java на практике Брайан Гетц - PullRequest
7 голосов
/ 03 февраля 2011

Java Concurrency на практике Брайан Гетц (Brian Goetz) представляет пример эффективного масштабируемого кэша для одновременного использования.Вот код для класса:

public class Memoizer<A, V> implements Computable<A, V> {
    private final ConcurrentMap<A, Future<V>> cache
        = new ConcurrentHashMap<A, Future<V>>();
    private final Computable<A, V> c;

    public Memoizer(Computable<A, V> c) { this.c = c; }

    public V compute(final A arg) throws InterruptedException {
        while (true) {
            Future<V> f = cache.get(arg);
            if (f == null) {
                Callable<V> eval = new Callable<V>() {
                    public V call() throws InterruptedException {
                        return c.compute(arg);
                    }
                };
                FutureTask<V> ft = new FutureTask<V>(eval);
                f = cache.putIfAbsent(arg, ft);
                if (f == null) { f = ft; ft.run(); }
            }
            try {
                return f.get();
            } catch (CancellationException e) {
                cache.remove(arg, f);
            } catch (ExecutionException e) {
                throw launderThrowable(e.getCause());
            }
        }
    } }

Возможно, глупый вопрос, но кто-нибудь может показать мне одновременное использование этого класса?Как в основном?

Ура, Агата

Ответы [ 2 ]

6 голосов
/ 03 февраля 2011

Вот пример, который вычисляет факториалы:

public static void main(String[] args) throws Exception {

    //create a memoizer that performs factorials
    final Memoizer<Integer, Integer> memo = new Memoizer<Integer, Integer> (new Computable<Integer, Integer>() {
        @Override
        public Integer compute(Integer a) {
            int result = 1 ;
            for(int i = 1 ; i < a ; i++){
                result = result*i;
            }
            return result;
        }
    });

    //now call the memoizer
    System.out.println(memo.compute(10));


    //call it with 10 threads concurrently
    ExecutorService exec = Executors.newFixedThreadPool(10);
    ExecutorCompletionService<Integer> compService = new ExecutorCompletionService<Integer>(exec);
    for(int i = 0 ; i < 15 ; i++){
        compService.submit(new Callable<Integer>(){
            @Override
            public Integer call() throws Exception {
                return memo.compute(5);
            }
        });
    }
    exec.shutdown();
    for(int i = 0 ; i < 15 ; i++){
        System.out.println(compService.take().get());
    }
}

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

1 голос
/ 03 февраля 2011

Я мог бы представить что-то вроде этого:

class PrimeDetector implements Computable<BigInteger, Boolean> {
  public Boolean compute(BigInteger number) {
    // detect whether the number is prime and return true if it is
  }
}

Memoizer<BigInteger, Boolean> primeMemoizer =
        new Memoizer<BigInteger, BigInteger[]>(new PrimeDetector());
boolean isPrime = primeMemoizer.compute(
        new BigInteger("5625945193217348954671586615478165774647538956473535"));
...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...