`
DavyJones2010
  • 浏览: 154872 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

Java SE: Effective Java Notes "Concurrency"

阅读更多

Use the Advanced Concurrent Tools instead of the legacy wait() and notify().

Java Advanced Concurrent Tools:

    1> Executor Framework: ExecutorService, Callable, Executors ...

    2> Concurrent Collection: ConcurrentMap, BlockingQueue ... (Is there any ConcurrentSet*(1) and ConcurrentList*(2) ?)

    3> Synchronizer: CountDownLatch, Semaphore, CyclicBarrier, Exchanger, Locks: (ReentrantLock, ReadLock, WriteLock)...

 

Never call an alien method from within a synchronized region.

1) Example for ConcurrentModificationException:

public class ConcurrentModificationTest {
	@Test(expected=ConcurrentModificationException.class)
	public void test() {
		Set<String> set = Sets.newHashSet("A", "B", "C");
		for (String str : set) {
			if ("B".equals(str)) {
				set.remove(str);
			}
		}
	}
}

    We cannot modify the set when iterating it.

    But how did JDK inspect this kind of issue(ConcurrentModification)?

final Entry<K,V> nextEntry() {
    if (modCount != expectedModCount)
        throw new ConcurrentModificationException(); // Exception is thrown here
    Entry<K,V> e = next;
    if (e == null)
        throw new NoSuchElementException();

    if ((next = e.next) == null) {
        Entry[] t = table;
        while (index < t.length && (next = t[index++]) == null)
           ;
    }
    current = e;
    return e;
}

    We can know that this exception is not thrown when we execute set.remove(str), it is thrown when we iterate the element just after we executing remove(str);

    Thus we can run across this exception by just jump out of this for-loop. But this shortcut is limited(can only remove one element for the whole loop) and deprecated(we can use a new filteredSet to store the filtered elements instead).

@Test
public void test() {
	Set<String> set = Sets.newHashSet("A", "B", "C");
	for (String str : set) {
		if ("B".equals(str)) {
			set.remove(str);
			break; // Here we just jump out of the loop, thus do not have a chance to execute nextEntry() and check modCount == expectedModCount
		}
	}
	assertEquals(2, set.size());
}

 

2. ObservableSet Example -"Effective Java 2nd Edition, Chapter 10"

public class ForwardingSet<E> implements Set<E> {
	private final Set<E> s;
	public ForwardingSet(Set<E> s) {
		this.s = s;
	}

	public void clear() {
		s.clear();
	}
	public boolean contains(Object o) {
		return s.contains(o);
	}
	public boolean isEmpty() {
		return s.isEmpty();
	}
	public int size() {
		return s.size();
	}
	public Iterator<E> iterator() {
		return s.iterator();
	}
	public boolean add(E e) {
		return s.add(e);
	}
	public boolean remove(Object o) {
		return s.remove(o);
	}
	public boolean containsAll(Collection<?> c) {
		return s.containsAll(c);
	}
	public boolean addAll(Collection<? extends E> c) {
		return s.addAll(c);
	}
	public boolean removeAll(Collection<?> c) {
		return s.removeAll(c);
	}
	public boolean retainAll(Collection<?> c) {
		return s.retainAll(c);
	}
	public Object[] toArray() {
		return s.toArray();
	}
	public <T> T[] toArray(T[] a) {
		return s.toArray(a);
	}
	@Override
	public boolean equals(Object o) {
		return s.equals(o);
	}
	@Override
	public int hashCode() {
		return s.hashCode();
	}
	@Override
	public String toString() {
		return s.toString();
	}
}
public class ObservableSet<E> extends ForwardingSet<E> {
	private final List<SetObserver<E>> observers = new ArrayList<SetObserver<E>>();

	public ObservableSet(Set<E> set) {
		super(set);
	}

	public void addObserver(SetObserver<E> observer) {
		synchronized (observers) {
			observers.add(observer);
		}
	}

	public boolean removeObserver(SetObserver<E> observer) {
		synchronized (observers) {
			return observers.remove(observer);
		}
	}

	@Override
	public boolean add(E element) {
		boolean added = super.add(element);
		if (added) {
			synchronized (observers) {
				for (SetObserver<E> observer : observers)
					observer.elementAdded(this, element);
			}
		}
		return added;
	}
}
@Test(expected = ConcurrentModificationException.class)
public void addTest() throws InterruptedException {
	ObservableSet<Integer> set = new ObservableSet<>(new HashSet<Integer>());

	set.addObserver(new SetObserver<Integer>() {
		@Override
		public void elementAdded(final ObservableSet<Integer> observalSet,
				Integer element) {
			System.out.println(element + " added to set");
			final SetObserver<Integer> setObserverInstance = this;
			if (23 == element) {
				observalSet.removeObserver(setObserverInstance);
			}
		}
	});

	for (int i = 0; i < 100; i++) {
		set.add(i);
	}
}

   1) We can find that because "set.add()" need current thread to get lock for "observers", and "observalSet.removeObserver()" need current thread to get lock for "observers" too,

       And because the intrinsic lock in Java is ReentrantLock, thus when we invoke "observalSet.removeObserver()" in main thread, we don't have to get the lock again, and thus ConcurrentModificationException will be thrown.

       Just it behaves exactely the same as the first example above.

    Another version of removeObserver:

@Test
public void addTest() throws InterruptedException {
	ObservableSet<Integer> set = new ObservableSet<>(new HashSet<Integer>());

	set.addObserver(new SetObserver<Integer>() {
		@Override
		public void elementAdded(final ObservableSet<Integer> observalSet,
				Integer element) {
			System.out.println(element);
			final SetObserver<Integer> observerInstance = this;
			if (23 == element) {
				new Thread(new Runnable() {
					@Override
					public void run() {
					observalSet.removeObserver(observerInstance);
					}
				}).start();
			}
		}
	});

	for (int i = 0; i < 100; i++) {
		set.add(i);
	}
}

    Here we created a new thread to call "observalSet.removeObserver()", and the new thread need to get lock "observers", but the lock is currently held by the main thread, thus the removal thread need to wait until the main thread loops over and relase the lock.

    The result is that "observalSet.removeObserver()" executed only after 100 elements added to set.
    And this is esay to jump into DeatLock:

public boolean isObserverEmpty() {
	synchronized (observers) {
		return observers.isEmpty();
	}
}
@Test
public void addTest() throws InterruptedException {
	ObservableSet<Integer> set = new ObservableSet<>(new HashSet<Integer>());

	set.addObserver(new SetObserver<Integer>() {
		@Override
		public void elementAdded(final ObservableSet<Integer> observalSet,
				Integer element) {
			System.out.println(element);
			final SetObserver<Integer> observerInstance = this;
			new Thread(new Runnable() {
				@Override
				public void run() {
					try {
					observalSet.removeObserver(observerInstance);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}).start();
		}
	});
	while (!set.isObserverEmpty()) {
		Thread.sleep(10);
	}
}

    The example above wil jump into DeadLock: Main thread hold the "observers" lock(Thread.sleep will not release this lock) and wait for the listener thread to delete observer; At the same time, the listener thread trying to get the "observers" lock in order to delete the observer.

    This is a typical deatlock example. But it has the same mechanism that applies in Java GUI Toolkit which lead to exception/deadlock/starvation in practice.

    The root reason why this kind of program is awkward/dangerous, is that it has elementeAdded() method which is designed to be override by client, but this method is just inside a synchronized region.

    "Inside a synchronized region, do not invoke a method that is designed to be overriden."

    "To avoid liveness and safety failures, never cede control to the client within a synchronized method or block."

 

 

Reference Links:
1) http://stackoverflow.com/questions/6916385/is-there-a-concurrent-list-in-javas-jdk

2) http://stackoverflow.com/questions/6992608/why-there-is-no-concurrenthashset-against-concurrenthashmap

 

分享到:
评论

相关推荐

    Reactive Streams in Java: Concurrency with RxJava, Reactor, and Akka Streams

    Get an easy introduction to reactive streams in Java to handle concurrency, data streams, and the propagation of change in today's applications. This compact book includes in-depth introductions to ...

    Java Lesson: Concurrency

    Java并发编程是Java平台的核心特性之一,它使得开发者可以创建能够充分利用多核处理器能力的高效应用程序。本课程将深入探讨Java中的并发概念,包括基础支持和高阶API,特别是`java.util.concurrent`包中的工具。 ...

    Java并发编程实践(java concurrency in practice)pdf (java多线程总结.ppt)

    《Java并发编程实践》是Java开发者必读的经典之作,由Brian Goetz等多位专家共同撰写。这本书深入浅出地探讨了Java平台上的并发问题,帮助读者理解和掌握如何编写高效、可靠且可维护的多线程应用程序。以下是该书...

    Reactive Streams in Java.pdf

    Reactive Streams in Java Concurrency with RxJava, Reactor, and Akka Streams. 2019年最新出版,清晰文字PDF,带目录书签。

    Java Concurrency in Practice JAVA并发编程实践(中英文版)

    Using the concurrency building blocks in java.util.concurrent Performance optimization dos and don'ts Testing concurrent programs Advanced topics such as atomic variables, nonblocking algorithms, ...

    Java Concurrency in Practice 无水印pdf

    Java Concurrency in Practice 英文无水印pdf pdf所有页面使用FoxitReader和PDF-XChangeViewer测试都可以打开 本资源转载自网络,如有侵权,请联系上传者或csdn删除 本资源转载自网络,如有侵权,请联系上传者...

    java并行编程(Java Concurrency in Practice) 英文版chm

    &lt;&lt;java并行编程&gt;&gt;英文版chm格式,英文名称&lt;Java Concurrency in Practice&gt;,一直想买这本书,但总是缺货,找到了电子版,分享给大家。 Java Concurrency in Practice By Brian Goetz, Tim Peierls, Joshua Bloch,...

    Java Concurrency in Practice

    Java Concurrency in practice

    Effective Concurrency

    Herb Sutter is a leading authority on software development. He is the best selling author of Exceptional C++ as well as three other books and hundreds of ...This is Effective Concurrency article, 1 to 25

    Java.7.A.Comprehensive.Tutorial

    Chapter 24 Concurrency Utilities Chapter 25 Security Chapter 26 Java Web Applications Chapter 27 JavaServer Pages Chapter 28 Javadoc Chapter 29 Application Deployment Chapter 30 Reflection Chapter 31 ...

    Java Concurrency in Practice JAVA并发编程实践中文版(全)

    Java Concurrency in Practice JAVA并发编程实践中文版(全)第二部分

    Java Concurrency in Practice.zip

    《Java Concurrency in Practice》是Java并发编程领域的一本经典著作,由Brian Goetz、Tim Peierls、Joshua Bloch、Joseph Bowles和Doug Lea等专家共同编写。这本书深入探讨了Java平台上的多线程和并发编程,旨在...

    Java并发实践英文版(Java Concurrency in Practice)

    本书由多位著名的Java专家共同编写,其中包括Java平台架构师Brian Goetz,以及《Effective Java》的作者Joshua Bloch等。 #### 二、并发编程的重要性 并发编程是现代软件开发中的一个关键领域,它允许程序在多个...

    JavaConcurrency:Java并发教程

    本教程"JavaConcurrency:Java并发教程"旨在深入探讨Java平台上的并发机制和最佳实践。 Java并发的核心概念包括线程、同步、互斥、死锁以及线程安全。在Java中,线程是并发执行的基本单元,通过创建Thread对象或者...

    Java Concurrency in Practice中文版

    《Java Concurrency in Practice》是Java并发编程领域的一本经典著作,由Brian Goetz、Tim Peierls、Joshua Bloch、Joe Bowbeer、David Holmes和Doug Lea合著,国内有热心人士进行了中文翻译,使得更多的中国开发者...

Global site tag (gtag.js) - Google Analytics