Java multithreaded learning - java.util.concurrent (2) Semaphore/FutureTask/Exchanger
3. Semaphore
Let's start with a detailed introduction to this class in the JDK 1.5 API:"A counting semaphore. Conceptually, semaphores maintain a license set. If necessary, each acquire() is blocked before the license is available, and then the license is obtained. Each release() adds a license, which may release a blocking acquirer. However, without using the actual license object, Semaphore only counts the number of licenses available and takes corresponding actions."
We usually use it to control thread access objects of an object.
For example, for a container, we specify that at most n threads can operate simultaneously.
Use signal quantities to simulate implementation
The code is as follows (refer to [JCIP])
import java.util.Collections; import java.util.HashSet; import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Semaphore; public class TestSemaphore { public static void main(String[] args) { ExecutorService exec = Executors.newCachedThreadPool(); TestSemaphore t = new TestSemaphore(); final BoundedHashSet<String> set = t.getSet(); for (int i = 0; i < 3; i++) {//Three threads operate add at the same time exec.execute(new Runnable() { public void run() { try { set.add(Thread.currentThread().getName()); } catch (InterruptedException e) { e.printStackTrace(); } } }); } for (int j = 0; j < 3; j++) {//Three threads operate remove at the same time exec.execute(new Runnable() { public void run() { set.remove(Thread.currentThread().getName()); } }); } exec.shutdown(); } public BoundedHashSet<String> getSet() { return new BoundedHashSet<String>(2);//Define a thread with boundary constraint 2 } class BoundedHashSet<T> { private final Set<T> set; private final Semaphore semaphore; public BoundedHashSet(int bound) { this.set = Collections.synchronizedSet(new HashSet<T>()); this.semaphore = new Semaphore(bound, true); } public void add(T o) throws InterruptedException { semaphore.acquire();//Semaphore controls the number of accessible threads set.add(o); System.out.printf("add:%s%n",o); } public void remove(T o) { if (set.remove(o)) semaphore.release();//Release the semaphore System.out.printf("remove:%s%n",o); } } }
Summary: Semaphore is commonly used for object pool control
4.FutureTask
Let's start with a detailed introduction to this class in the JDK 1.5 API:
Canceled asynchronous computing. The basic implementation of Future is provided by using the methods of starting and canceling calculation, querying whether calculation is completed or not, and obtaining calculation results. The result can be obtained only when the calculation is completed; if the calculation is not completed, the get method is blocked. Once the calculation is completed, the calculation cannot be restarted or cancelled.
Callable or Runnable objects can be wrapped using FutureTask. Because FutureTask implements Runnable, FutureTask can be submitted to Executor for execution.
In addition to being a separate class, this class also provides protected functionality, which may be useful in creating custom task classes. "
Application example: Our algorithm has a time-consuming operation. In programming, we want to separate it into a module and call it as it returns immediately and can be cancelled at any time.
The code is as follows (refer to [JCIP])
import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.FutureTask; public class TestFutureTask { public static void main(String[] args) { ExecutorService exec=Executors.newCachedThreadPool(); FutureTask<String> task=new FutureTask<String>(new Callable<String>(){//FutrueTask's construction parameter is a Callable interface @Override public String call() throws Exception { return Thread.currentThread().getName();//This can be an asynchronous operation }}); try { exec.execute(task);//FutureTask is actually a thread String result=task.get();//Get the result of the asynchronous calculation, and if it does not return, it will always block and wait. System.out.printf("get:%s%n",result); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } }
Summary: FutureTask actually creates a new thread to execute independently, so that the thread has a return value, which is convenient for programming.
5.
Exchanger
Let's start with a detailed introduction to this class in the JDK 1.5 API:
"Synchronization points of threads that can pair and exchange elements in pairs. Each thread presents a method on an entry to the exchange method, matches the partner thread, and receives the partner's object on return. Exchanger may be considered a two-way form of SynchronousQueue. Exchanger may be useful in applications such as genetic algorithms and pipeline design. "
Application example: There are two caches, two threads fill and take to two caches respectively, if and only if one is full, two caches exchange.
The code is as follows (referring to the example given online: http://hi.baidu.com/webidea/blog/item/2995e731e53ad5a55fdf0e7d.html)
Summary: Exchanger is useful in specific usage scenarios (data interaction between two partner threads)import java.util.ArrayList; import java.util.concurrent.Exchanger; public class TestExchanger { public static void main(String[] args) { final Exchanger<ArrayList<Integer>> exchanger = new Exchanger<ArrayList<Integer>>(); final ArrayList<Integer> buff1 = new ArrayList<Integer>(10); final ArrayList<Integer> buff2 = new ArrayList<Integer>(10); new Thread(new Runnable() { @Override public void run() { ArrayList<Integer> buff = buff1; try { while (true) { if (buff.size() >= 10) { buff = exchanger.exchange(buff);//Start interacting with another thread System.out.println("exchange buff1"); buff.clear(); } buff.add((int)(Math.random()*100)); Thread.sleep((long)(Math.random()*1000)); } } catch (InterruptedException e) { e.printStackTrace(); } } }).start(); new Thread(new Runnable(){ @Override public void run() { ArrayList<Integer> buff=buff2; while(true){ try { for(Integer i:buff){ System.out.println(i); } Thread.sleep(1000); buff=exchanger.exchange(buff);//Start exchanging data with another thread System.out.println("exchange buff2"); } catch (InterruptedException e) { e.printStackTrace(); } } }}).start(); } }