Сообщений 36 Оценка 6 Оценить |
At this writing, multicore processors are just now becoming inexpensive enough for midrange desktop systems. Not coincidentally, many development teams are noticing more and more threading-related bug reports in their projects. In a recent post on the NetBeans developer site, one of the core maintainers observed that a single class had been patched 14 times to fix threading-related problems. Dion Almaer, former editor of TheServerSide, recently blogged (after a painful debugging session that ultimately revealed a threading bug) that most Java programs are so rife with concurrency bugs that they work only "by accident".
Indeed, developing, testing and debugging multithreaded programs can be extremely difficult because concurrency bugs do not manifest themselves predictably. And when they do surface, it is often at worst possible time - in production, under heavy load.
One of the challenges of developing concurrent programs in Java is the mismatch between concurrency features offered by the platform and how developers need to think about concurrency in their programs. The language provides low-level mechanisms such as synchronization and condition waits, but these mechanisms must be used consistently to implement application-level protocols or policies. Without such policies, it is all too easy to create programs that compile and appear to work but are nevertheless broken. Many otherwise excellent books on concurrency fall short on their goal by focusing excessively on low-level mechanisms and APIs rather than design-level policies and patterns.
Java 5.0 is a huge step forward for the development of concurrent applications in Java, providing new higher-level components and additional low-level mechanisms that make it easier for novices and experts alike to build concurrent applications. The authors are primary members of the JCP Expert Group that created these facilities; in addition to describing their behavior and features, we present the underlying design patterns and anticipated usage scenarios that motivated their inclusion in the platform libraries.
Our goal is to give readers a set of design rules and mental models that make it easier - and more fun - to build correct, performant concurrent classes and applications in Java.
Книга будет полезна в первую очередь для Java разработчиков. Все повествование в книге идет вокруг джавовских примитивов синхронизации и классов, полезных при написании параллельных программ. Особого растеканию мыслию по древу в сторону общей теории написания параллельных программ я не заметил. Как и написано в предисловии, книгу отличает практический подход к изложению. В ней вкратце упоминается класс Java (обычно в виде списка прототипов его методов), а затем идет развернутое описание того, в каких случаях его полезно использовать. В книге очень много небольших листингов (в среднем около 20 на главу). В них отражаются все моменты, описываемые в тексте книги. Например, в 6-ой главе почти все листинги "крутятся" вокруг различных реализаций и способов использования интерфейса Executor. Очень сильной стороной книги я считаю то, что в ней прекрасно описаны высокоуровневые конструкции для написания параллельных программ, тогда как большинство увиденных мною глав в различных книгах крутилось именно вокруг низкоуровневой синхронизации (которая во многих случаях просто неуместна при наличии высокоуровневых примитивов). У книги есть официальный сайт: http://javaconcurrencyinpractice.com/ , где тоже есть кое-что интересное.
Хочу привести один пример законченного класса из этой книги. Класс реализует мемоизацию - процесс запоминания ранее вычисленных значений функции от ее аргументов. Например, если ранее уже было посчитано f(27), то при следующем таком же вызове значение функции считаться не будет. Вместо этого будет возвращено ранее сохраненное значение.
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 IntrruptedException { 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()); } } } public static RuntimeException launderThrowable(Throwable t) { if (t instanceof RuntimeException) return (RuntimeException)t; else if (t instanceof Error) throw (Error)t; else throw new IllegalStateException("Not unchecked", t); } } |
И пример использования данного класса:
public class Factorizer implements Servlet { private final Computable<BigInteger, BigInteger[]> cc = new Computable<BigInteger, BigInteger[]>() { public BigInteger[] compute(BigInteger arg) { return factor(arg); } }; private final Computable<BigInteger, BigInteger[]> cache = new Memoizer<BigInteger, BigInteger[]>(cc); public void service(ServletRequest req, ServletResponse resp) { try { BigInteger i = extractFromRequest(req); encodeIntoResponse(resp, cache.compute(i)); } catch (InterruptedException e) { encodeError(resp, "factorization interrupted"); } } } |
Сообщений 36 Оценка 6 Оценить |