1. Overview
If you read Java's source code, the most common code authors include: Doug Lea, Mark Reinhold, Josh Bloch, Arthur van Hoff, Neal Gafter, Pavani Diwanji, and more. The basic of the Java.util.concurrent package is Doug Lea's name. Doug Lea, the most influential individual in Java, contributes directly to the design of Java collections and util.concurrent.
An important feature in JDK1.5 is that the Util.concurrent package and its sub-packages (which are not part of our panel discussion) include many of the features in JDK1.5, such as generics, unpacking/encapsulation, etc. In this series of topics, we have introduced some of the main features of the Util.concurrent package, such as: Blockingqueue, Threadpoolexecutor, executors, and so on. In this article, we introduce the other threading features in this package.
2. Callable with return value
In the previous article, we mentioned that the run () method in the Java thread-related runnable interface did not provide a return value, as follows:
......public void run() { ......}......
If you want thread A to finish, get the return value, and then proceed to a business. It is recommended that you use the thread definition interface provided in JDK1.5 with "Execute return value": Callable.
If you also need more complex control logic for the execution of multiple threads, you need the synchronization mechanism we discussed earlier and the tools in the Java.util.concurrent.locks package in JDK1.5 to work together to achieve the effect.
JDK1.5 's Java.util.concurrent package provides a callable interface and a set of related mechanisms to help programmers perform the above functions safely, quickly and concisely (after the thread executes, it returns an execution result). The interface method that needs to be implemented in the callable interface is call (), which has a generalized return value of V that can help you return any one of the object's results defined. The interface source code is as follows:
public interface Callable<V> { /** * Computes a result, or throws an exception if unable to do so. * * @return computed result * @throws Exception if unable to compute a result */ throws Exception;}
Let's take a simple code to see how the callable interface completes the return and activation of the waiting thread for the execution result:
PackageTest.thread.base.callfurther;Importjava.util.concurrent.Callable;ImportJava.util.concurrent.ExecutorService;ImportJava.util.concurrent.Executors;ImportJava.util.concurrent.Future;ImportJava.util.concurrent.TimeUnit;/** * Testing threads that can monitor status * @author Yinwenjie * @param <V> * *Public class mycallablethread<V extends Entity> Implements callable<V> { PrivateV resultsentity; Public mycallablethread (V param) { This. resultsentity = param; }/* (non-javadoc) * @see java.util.concurrent.callable#call () */ @OverridePublic V Call ()throwsException {Try{//wait for a period of time to simulate the business execution processSynchronized ( This) { This. Wait ( the); }//Set return results This. Resultsentity.setstatus (1); }Catch(Exception e) {//Execution error, also set This. Resultsentity.setstatus (-1); }return This. resultsentity; } public static void Main (string[] args)throwsException {//This is a model object that you define. There's a status attribute insideMycallablethread<entity> Callablethread =NewMycallablethread<entity> (NewEntity ());//callable need to be executed in the thread poolExecutorservice es = Executors.newfixedthreadpool (1); future<entity> future = Es.submit (Callablethread);the//main thread will wait here to know that the Callablethread task execution is completeEntity result = Future.get (); System.out.println ("Result.status ="+ Result.getstatus ());//Stop thread pool workEs.shutdown (); Es.awaittermination (Long.max_value, timeunit.days); }}
The usage code given above includes the following practical actions:
The entity class is a class that is designed to record the return results of a thread's execution by our own definition. In fact, for Mycallablethread, as long as all subclasses of the entity are inherited, it can be used as its generalization value.
currently callable defined thread tasks, which can only be placed in the thread pool, are executed by the tasks in the thread pool . There is no runnable interface like the new thread (new Mydefindrunnable ()) and start () threads run as.
The future is used to describe the execution state of the current task thread. You can use methods such as Isdone, iscancelled, and so on to get the execution state of the current task thread.
The Get method in the future interface will be the current thread going into a blocking state. Until the target thread finishes executing and gets the result of the target thread's return .
Waits if necessary for the computation to complete, and then retrieves its result.
Returns: The computed result
Throws:
Cancellationexception-if the computation was cancelled
Executionexception-if the computation threw an exception
Interruptedexception-if the current thread is interrupted while waiting
3, JDK new feature lock: Java.util.concurrent.locks bag
Java.util.concurrent has a locks child package that provides a new locking mechanism designed in the JDK1.5 version. Among the most important are two types of locks: Reentrantlock Universal Lock and Reentrantreadwritelock read-write lock. In this summary we mainly introduce the use of these two new lock patterns.
3-1, Lock->reentrantlock Universal lock
In the JDK1.5 version, Doug Lea added two new object lock methods, Reentrantlock and Reentrantreadwritelock. In the previous release, if we were to lock an object that was manipulated in a thread, the following is the syntax:
......synchronized (ThreadLock.WAIT_OBJECT) { ThreadLock.LOGGER.info("做了一些事情。。。。");}......
This lock-in object is checked synchronously, and the code within the synchronization boundary allows only a single thread A to enter, unless thread a exits the synchronization boundary or enters a blocking state by means of wait, which allows other threads to access it.
You also need to pay special attention to interrupt exceptions when using the Synchronized keyword. This is actually because the JVM does not allow the thread that is waiting for the sync lock to stop (this is a more in-depth knowledge point).
Then if you use Reentrantlock for blocking control of threads in shared resources by multiple threads, it is much simpler than using the Synchronized keyword (at least from a superficial perspective). And you don't have to pay special attention to interrupt anomalies (at least in terms of surface phenomena).
Remember our basic threading operations in thread Base: Thread (2)--java (top) This article gives the simplest code for using object locks in multithreaded situations? OK, don't go through this article deliberately, here we give one more time (in order to save space, only to the important code snippet):
....../** * Lock the object * *Private Static FinalObject Wait_object =NewObject (); Thread Threada =NewThread (NewRunnable () {@Override Public void Run() {//Check the ' object lock ' status. synchronized(Threadlock.wait_object) {ThreadLock.LOGGER.info ("did some things .... "); } }}); Thread threadb =NewThread (NewRunnable () {@Override Public void Run() {//Check the ' object lock ' status. synchronized(Threadlock.wait_object) {ThreadLock.LOGGER.info ("did something else .... "); }}); Threada.start (); Threadb.start ();
Now we use the Reentrantlock method to make changes to the previous code:
...... Public void Test() {final Reentrantlock Objectlock =NewReentrantlock ();NewThread () { Public void Run() {Objectlock.Lock(); TestReentrantLock.LOG.info ("did some things .... "); Objectlock.unlock (); }}.start ();NewThread () { Public void Run() {Objectlock.Lock(); TestReentrantLock.LOG.info ("did something else .... "); Objectlock.unlock (); }}.start ();} ......
It is clear that the following rewrite code using the Reentrantlock method is not much better understood. In fact, the most intuitive understanding is that the boundaries of the Synchronized keyword are replaced by the lock and unlock methods (but not in fact). At least thread you don't need to care about interrupt exceptions.
3-2. Readwritelock->reentrantreadwritelock read/write lock
In the Java.util.concurrent.locks package, a Reentrantreadwritelock tool is also available. Obviously, the name of the class understands its meaning, and more than one thread will lock the read and write operations of the specified object separately.
We can use the following code to get the write lock of an object
WriteLock writeLock = objectLock.writeLock();
Use the following code to get the read lock for the object:
readLock = objectLock.readLock();
So how does an object's write lock and read lock affect each other? This needs to be described separately, first of all, let's discuss what happens when a thread can get a read lock on an object:
- If no thread gets the write lock for the object.
- Although the thread acquires a write lock on the object, it is the thread that is currently requesting a read lock
Then whether the thread gets the read lock of the object at the current time does not affect the current threads continuing to fetch the object's read lock . What happens when a thread can get a write lock on an object:
- No thread has ever fetched a read lock on this object.
- No thread has ever acquired a write lock on this object.
Note that there is no "though" in this statement. That is, the following notation in the same thread would result in a deadlock:
......ReadLock readLock = objectLock.readLock();readLock.lock();WriteLock writeLock = objectLock.writeLock();// 线程操作会被一直阻塞在这里writeLock.lock();......
However, the following notation in the same thread is not a problem:
......WriteLock writeLock = objectLock.writeLock();writeLock.lock();ReadLock readLock = objectLock.readLock();readLock.lock();......
Here are all the sample code:
PackageTest.thread.reentrant;ImportJava.util.concurrent.locks.ReentrantReadWriteLock;ImportJava.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;ImportJava.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;ImportOrg.apache.commons.logging.Log;ImportOrg.apache.commons.logging.LogFactory;ImportOrg.apache.log4j.BasicConfigurator; Public class testreadwritereentrantlock { Static{basicconfigurator.configure (); }/** * Log * * Private Static FinalLog log = Logfactory.getlog (Testreadwritereentrantlock.class); Public Static void Main(string[] args)throwsruntimeexception {NewTestreadwritereentrantlock (). Test (); } Public void Test() {FinalReentrantreadwritelock Objectlock =NewReentrantreadwritelock (); Thread Thread1 =NewThread () { Public void Run() {Writelock writelock = Objectlock.writelock (); Writelock.lock (); TestReadWriteReentrantLock.LOG.info ("did something to write about .... "); Writelock.unlock (); } }; Thread thread2 =NewThread () { Public void Run() {Writelock writelock = Objectlock.writelock (); Writelock.lock (); TestReadWriteReentrantLock.LOG.info ("did something else to write about .... "); Writelock.unlock (); } }; Thread thread3 =NewThread () { Public void Run() {Readlock readlock = Objectlock.readlock (); Readlock.lock (); TestReadWriteReentrantLock.LOG.info ("did something to read the operation .... "); Readlock.unlock (); } };//thread1, Thread2, thread3 in the course of operation, will be in accordance with the law we described earlier, interactionThread1.start (); Thread2.start ();//You can use the Thread1.interrupt () directive to reentrantlock images. //You can see that the thread1 does not throw a Interruptexception exception after the lock is added //At least in our usage mode, no exception is thrown //Thread1.interrupt ();Thread3.start (); }}
It is important to note that in most cases you use the Sycnchronized keyword or use the Reentrantlock method, which is not a problem (this is because the sycnchronized is not really blocking in the case of 90%). There is absolutely no need to change the sycnchronized keyword in your historical code version in order to use a better-performing reentrantlock approach .
Later, if there is time, I will discuss with you the different ways of sycnchronized and reentrantlock in working principle. But because I spent too much time on this column, I had to postpone it. If you want to get a deeper understanding of how they work, here I recommend an article: (http://www.ibm.com/developerworks/library/j-jtp10264/)
Below, we will take a "race" example to explain some of the line programming tools (including Semaphore, Countdownlatch, and java.util.concurrent.atomic sub-packages) in the JDK1.5 environment. and review the topic of the knowledge Points: Synchronization fast, lock, thread pool, blockingqueue, callable and so on. Of course, the way data is passed between threads.
(next)
Thread Base: jdk1.5+ (8)--line assigns characteristics (top)