Kĩ thuật lập trình - Chương 23: Multithreading
Even when using a bounded buffer, it is possible that a producer thread could fill the buffer, which would force the producer to wait until a consumer consumed a value to free an element in the buffer. Similarly, if the buffer is empty at any given time, a consumer thread must wait until the producer produces another value. The key to using a bounded buffer is to optimize the buffer size to minimize the amount of thread wait time, while not wasting space.
124 trang |
Chia sẻ: huyhoang44 | Lượt xem: 822 | Lượt tải: 0
Bạn đang xem trước 20 trang tài liệu Kĩ thuật lập trình - Chương 23: Multithreading, để xem tài liệu hoàn chỉnh bạn click vào nút DOWNLOAD ở trên
23Multithreading1The most general definition of beauty Multeity in Unity.Samuel Taylor ColeridgeDo not block the way of inquiry.Charles Sanders PeirceA person with one watch knows what time it is; a person with two watches is never sure.Proverb2Learn to labor and to wait.Henry Wadsworth LongfellowThe world is moving so fast these days that the man who says it can’t be done is generally interrupted by someone doing it.Elbert Hubbard3OBJECTIVESIn this chapter you will learn: What threads are and why they are useful.How threads enable you to manage concurrent activities.The life cycle of a thread.Thread priorities and scheduling.To create and execute Runnables.Thread synchronization.What producer/consumer relationships are and how they are implemented with multithreading.To enable multiple threads to update Swing GUI components in a thread-safe manner.About interfaces Callable and Future, which you can use with threading to execute tasks that return results.423.1 Introduction23.2 Thread States: Life Cycle of a Thread23.3 Thread Priorities and Thread Scheduling23.4 Creating and Executing Threads 23.4.1 Runnables and the Thread Class 23.4.2 Thread Management with the Executor Framework23.5 Thread Synchronization23.6 Producer/Consumer Relationship without Synchronization 23.5.1 Unsynchronized Data Sharing 23.5.2 Synchronized Data Sharing—Making Operations Atomic523.7 Producer/Consumer Relationship: ArrayBlockingQueue23.8 Producer/Consumer Relationship with Synchronization23.9 Producer/Consumer Relationship: Bounded Buffers23.10 Producer/Consumer Relationship: The Lock and Condition Interfaces23.11 Multithreading with GUI23.12 Other Classes and Interfaces in java.util.concurrent 23.11.1 Performing Computations in a Worker Thread 23.11.2 Processing Intermediate Results wit SwingWorker23.13 Wrap-Up623.1 IntroductionThe human body performs a great variety of operations in parallel—or concurrentlyComputers, too, can perform operations concurrentlyOnly computers that have multiple processors can truly execute multiple instructions concurrentlyOperating systems on single-processor computers create the illusion of concurrent execution by rapidly switching between activities, but on such computers only a single instruction can execute at once723.1 IntroductionMost programming languages do not enable you to specify concurrent activitiesHistorically, concurrency has been implemented with operating system primitives available only to experienced systems programmersAda made concurrency primitives widely available to defense contractors building military command-and-control systemsnot widely used in academia and industryJava makes concurrency available to you through the language and APIs8Performance Tip 23.1A problem with single-threaded applications that can lead to poor responsiveness is that lengthy activities must complete before others can begin. In a multithreaded application, threads can be distributed across multiple processors (if available) so that multiple tasks execute concurrently and the application can operate more efficiently. Multithreading can also increase performance on single-processor systems that simulate concurrency—when one thread cannot proceed (because, for example, it is waiting for the result of an I/O operation), another can use the processor.923.1 IntroductionAn application of concurrent programmingStart playback of an audio clip or a video clip while the clip downloadssynchronize (coordinate the actions of) the threads so that the player thread doesn’t begin until there is a sufficient amount of the clip in memory to keep the player thread busyThe Java Virtual Machine (JVM) creates threads to run a program, the JVM also may create threads for performing housekeeping tasks such as garbage collectionProgramming concurrent applications is difficult and error-proneFollow some simple guidelinesUse existing classes from the Java API such as the ArrayBlockingQueue class that manage synchronization for you. The classes in the Java API are written by experts, have been fully tested and debugged, operate efficiently and help you avoid common traps and pitfalls. If you find that you need more custom functionality than that provided in the Java APIs, you should use the synchronized keyword and Object methods wait, notify and notifyAllIf you need even more complex capabilities, then you should use the Lock and Condition interfaces 1023.1 IntroductionThe Lock and Condition interfaces should be used only by advanced programmers who are familiar with the common traps and pitfalls of concurrent programming1123.2 Thread States: Life Cycle of a ThreadA thread occupies one of several thread states (Fig. 23.1)A new thread begins its life cycle in the new state. When the program starts the thread it enters the runnable state. considered to be executing its taskRunnable thread transitions to the waiting state while it waits for another thread to perform a tasktransitions back to the runnable state only when another thread notifies the waiting thread to continue executingA runnable thread can enter the timed waiting state for a specified interval of timetransitions back to the runnable state when that time interval expires or when the event it is waiting for occurs. 12Fig. 23.1 | Thread life-cycle UML state diagram.1323.2 Thread States: Life Cycle of a ThreadTimed waiting and waiting threads cannot use a processor, even if one is available. A runnable thread can transition to the timed waiting state if it provides an optional wait interval when it is waiting for another thread to perform a task. returns to the runnable state when it is notified by another thread, or the timed interval expiresA thread also enters the timed waiting state when put to sleepremains in the timed waiting state for a designated period of time then returns to the runnable stateA runnable thread transitions to the blocked state when it attempts to perform a task that cannot be completed immediately and it must temporarily wait until that task completes. A blocked thread cannot use a processor, even if one is availableA runnable thread enters the terminated state (sometimes called the dead state) when it successfully completes its task or otherwise terminates (perhaps due to an error).1423.2 Thread States: Life Cycle of a ThreadAt the operating system level, Java’s runnable state typically encompasses two separate states (Fig. 23.2). Operating system hides these states from the JVMA runnable thread first enters the ready stateWhen thread is dispatched by the OS it enters the running stateWhen the thread’s quantum expires, the thread returns to the ready state and the operating system dispatches another threadTransitions between the ready and running states are handled solely by the operating system15Fig. 23.2 | Operating system’s internal view of Java’s runnable state.1623.3 Thread Priorities and Thread SchedulingEvery Java thread has a thread priority that helps the operating system determine the order in which threads are scheduledPriorities range between MIN_PRIORITY (a constant of 1) and MAX_PRIORITY (a constant of 10)By default, every thread is given priority NORM_PRIORITY (a constant of 5)Each new thread inherits the priority of the thread that created it1723.3 Thread Priorities and Thread SchedulingInformally, higher-priority threads are more important to a program and should be allocated processor time before lower-priority threadsDoes not guarantee the order in which threads executeTimeslicingenables threads of equal priority to share a processorwhen thread’s quantum expires, processor is given to the next thread of equal priority, if one is availableThread scheduler determines which thread runs nextHigher-priority threads generally preempt the currently running threads of lower priorityknown as preemptive schedulingPossible indefinite postponement (starvation)18Portability Tip 23.1Thread scheduling is platform dependent—the behavior of a multithreaded program could vary across different Java implementations.19Fig. 23.3 | Thread-priority scheduling.20Portability Tip 23.2When designing multithreaded programs consider the threading capabilities of all the platforms on which the programs will execute. Using priorities other than the default will make your programs’ behavior platform specific. If portability is your goal, don’t adjust thread priorities.2123.4 Creating and Executing ThreadsRunnable interface (of package java.lang)Runnable object represents a “task” that can execute concurrently with other tasksMethod run contains the code that defines the task that a Runnable object should perform2223.4.1 Runnables and the Thread ClassMethod sleep throws a (checked) InterruptedException if the sleeping thread’s interrupt method is calledThe code in method main executes in the main thread, a thread created by the JVM23OutlinePrintTask.java(1 of 2 ) Implement Runnable to define a task that can execute concurrently24OutlinePrintTask.java(2 of 2 ) Define task in method run25OutlineThreadCreator .java(1 of 2 ) Create Threads to execute each new Runnable objectStart the Threads to begin processing the concurrent tasks26OutlineThreadCreator .java(2 of 2 ) 2723.4.2 Thread Management with the Executor FrameworkRecommended that you use the Executor interface to manage the execution of Runnable objects An Executor object creates and manages a thread pool to execute RunnablesExecutor advantages over creating threads yourselfReuse existing threads to eliminate new thread overheadImprove performance by optimizing the number of threads to ensure that the processor stays busyExecutor method execute accepts a Runnable as an argumentAssigns each Runnable it receives to one of the available threads in the thread poolIf none available, creates a new thread or waits for a thread to become available2823.4.2 Thread Management with the Executor FrameworkInterface ExecutorService package java.util.concurrentextends Executordeclares methods for managing the life cycle of an ExecutorObjects of this type are created using static methods declared in class Executors (of package java.util.concurrent)Executors method newCachedThreadPool obtains an ExecutorService that creates new threads as they are needed ExecutorService method execute returns immediately from each invocationExecutorService method shutdown notifies the ExecutorService to stop accepting new tasks, but continues executing tasks that have already been submitted29OutlineTaskExecutor .java(1 of 2 ) Creates an ExecutorService that manages a cached thread pool30OutlineTaskExecutor .java(2 of 2 ) Use the ExecutorService’s execute method to assign each new Runnable object to a thread in the thread poolPrevent the ExecutorService from accepting additional Runnable objects3123.5 Thread SynchronizationCoordinates access to shared data by multiple concurrent threadsIndeterminate results may occur unless access to a shared object is managed properlyGive only one thread at a time exclusive access to code that manipulates a shared objectOther threads waitWhen the thread with exclusive access to the object finishes manipulating the object, one of the threads that was waiting is allowed to proceedMutual exclusion3223.5 Thread SynchronizationJava provides built-in monitors to implement synchronizationEvery object has a monitor and a monitor lock. Monitor ensures that its object’s monitor lock is held by a maximum of only one thread at any timeCan be used to enforce mutual exclusionTo enforce mutual exclusionthread must acquire the lock before it can proceed with its operationother threads attempting to perform an operation that requires the same lock will be blocked until the first thread releases the lock3323.5 Thread Synchronizationsynchronized statement Enforces mutual exclusion on a block of codesynchronized ( object ){ statements} // end synchronized statementwhere object is the object whose monitor lock will be acquired (normally this)A synchronized method is equivalent to a synchronized statement that encloses the entire body of a method3423.5.1 Unsynchronized Data SharingExecutorService method awaitTermination forces a program to wait for threads to complete executionreturns control to its caller either when all tasks executing in the ExecutorService complete or when the specified timeout elapsesIf all tasks complete before awaitTermination times out, returns true; otherwise returns false35OutlineSimpleArray.java(1 of 2 ) Track where next item will be placed36OutlineSimpleArray.java(2 of 2 ) Place the itemSpecify where next item will be placed37OutlineArrayWriter.java38OutlineSharedArrayTest .java(1 of 2 ) Both ArrayWriters share the same SimpleArray object39OutlineSharedArrayTest .java(2 of 2 ) 4023.5.2 Synchronized Data Sharing—Making Operations AtomicSimulate atomicity by ensuring that only one thread carries out a set of operations at a timeImmutable data shared across threadsdeclare the corresponding data fields final to indicate that variables’ values will not change after they are initialized41Software Engineering Observation 23.1Place all accesses to mutable data that may be shared by multiple threads inside synchronized statements or synchronized methods that synchronize on the same lock. When performing multiple operations on shared data, hold the lock for the entirety of the operation to ensure that the operation is effectively atomic. 42OutlineSimpleArray.java(1 of 3 ) Using synchronized prevents more than one thread at a time from calling this method on a specific SimpleArray object 43OutlineSimpleArray.java(2 of 3 ) 44OutlineSimpleArray.java(3 of 3 ) 45Performance Tip 23.2Keep the duration of synchronized statements as short as possible while maintaining the needed synchronization. This minimizes the wait time for blocked threads. Avoid performing I/O, lengthy calculations and operations that do not require synchronization with a lock held.46Good Programming Practice 23.1Always declare data fields that you do not expect to change as final. Primitive variables that are declared as final can safely be shared across threads. An object reference that is declared as final ensures that the object it refers to will be fully constructed and initialized before it is used by the program and prevents the reference from pointing to another object.4723.6 Producer/Consumer Relationship without SynchronizationMultithreaded producer/consumer relationshipProducer thread generates data and places it in a shared object called a bufferConsumer thread reads data from the bufferOperations on the buffer data shared by a producer and a consumer are state dependentShould proceed only if the buffer is in the correct stateIf in a not-full state, the producer may produceIf in a not-empty state, the consumer may consumeMust synchronize access to ensure that data is written to the buffer or read from the buffer only if the buffer is in the proper state48OutlineBuffer.javaInterface Buffer that will be implemented in each of our Producer/Consumer examples49OutlineProducer.java(1 of 2 ) Class Producer represents a Runnable task that places values in a BufferDefines the Producer’s taskPlaces a value in the Buffer50OutlineProducer.java(2 of 2 ) 51OutlineConsumer.java(1 of 2 ) Class Consumer represents a Runnable task that reads values from a BufferDefines the Consumer’s taskReads a value from the Buffer52OutlineConsumer.java(2 of 2 ) 53OutlineUnsynchronized Buffer.javaUnsynchronized implementation of interface Buffer54OutlineSharedBufferTest.java(1 of 3 ) Producer and Consumer share the same unsynchronized Buffer55OutlineSharedBufferTest.java(2 of 3 ) 56OutlineSharedBufferTest.java(3 of 3 ) 5723.7 Producer/Consumer Relationship: ArrayBlockingQueueArrayBlockingQueue (package java.util.concurrent)Good choice for implementing a shared bufferImplements interface BlockingQueue, which extends interface Queue and declares methods put and takeMethod put places an element at the end of the BlockingQueue, waiting if the queue is fullMethod take removes an element from the head of the BlockingQueue, waiting if the queue is emptyStores shared data in an arrayArray size specified as a constructor argument Array is fixed in size58OutlineBlockingBuffer .java(1 of 2 ) Synchronized implementation of interface Buffer that uses an ArrayBlockingQueue to implement the synchronizationCreates a single element buffer of type ArrayBlockingQueue59OutlineBlockingBuffer .java(2 of 2 ) 60OutlineBlockingBuffer Test.java(1 of 2 ) Producer and Consumer share the same synchronized Buffer61OutlineBlockingBuffer Test.java(2 of 2 ) 6223.8 Producer/Consumer Relationship with SynchronizationCan implement a shared using the synchronized keyword and Object methods wait, notify and notifyAllcan be used with conditions to make threads wait when they cannot perform their tasksA thread that cannot continue with its task until some condition is satisfied can call Object method waitreleases the monitor lock on the objectthread waits in the waiting state while the other threads try to enter the object’s synchronized statement(s) or method(s) A thread that completes or satisfies the condition on which another thread may be waiting can call Object method notify allows a waiting thread to transition to the runnable state the thread that was transitioned can attempt to reacquire the monitor lockIf a thread calls notifyAll, all the threads waiting for the monitor lock become eligible to reacquire the lock63Common Programming Error 23.1It is an error if a thread issues a wait, a notify or a notifyAll on an object without having acquired a lock for it. This causes an IllegalMonitorStateException. 64Error-Prevention Tip 23.1It is a good practice to use notifyAll to notify waiting threads to become runnable. Doing so avoids the possibility that your program would forget about waiting threads, which would otherwise starve.65OutlineSynchronized Buffer.java(1 of 3 ) Synchronized implementation of interface Buffer that uses monitors and monitor locksSynchronized method that allows a Producer to write a new value only if the buffer is emptyProducer cannot write so it must waitNotify waiting Consumer that a value is now available66OutlineSynchronized Buffer.java(2 of 3 ) Synchronized method that allows a Consumer to read a value only if the buffer is fullConsumer cannot read so it must wait67OutlineSynchronized Buffer.java(3 of 3 ) Notify waiting Producer that a value is now available68Error-Prevention Tip 23.2Always invoke method wait in a loop that tests the condition the task is waiting on. It is possible that a thread will reenter the runnable state (via a timed wait or another thread calling notifyAll) before the condition is satisfied. Testing the condition again ensures that the thread will not erroneously execute if it was notified early.69OutlineSharedBuffer Test2.java(1 of 3 ) Producer and Consumer share the same synchronized Buffer70OutlineSharedBuffer Test2.java(2 of 3 ) 71OutlineSharedBuffer Test2.java(3 of 3 ) 7223.9 Producer/Consumer Relationship: Bounded BuffersCannot make assumptions about the relative speeds of concurrent Bounded buffer Used to minimize the amount of waiting time for threads that share resources and operate at the same average speedsKey is to provide the buffer with enough locations to handle the anticipated “extra” productionArrayBlockingQueue is a bounded buffer that handles all of the synchronization details for you 73Performance Tip 23.3Even when using a bounded buffer, it is possible that a producer thread could fill the buffer, which would force the producer to wait until a consumer consumed a value to free an element in the buffer. Similarly, if the buffer is empty at any given time, a consumer thread must wait until the producer produces another value. The key to using a bounded buffer is to optimize the buffer size to minimize the amount of thread wait time, while not wasting space..74OutlineCircularBuffer .java(1 of 3 ) Determine whether buffer is fullSpecify next write position in buffer75OutlineCircularBuffer .java(2 of 3 ) Determine whether buffer is emptySpecify the next read location in the buffer76OutlineCircularBuffer .java(3 of 3 ) 77OutlineCircularBuffer Test.java(1 of 5 ) Producer and Consumer share the same synchronized circular Buffer78OutlineCircularBuffer Test.java(2 of 5 ) 79OutlineCircularBuffer Test.java(3 of 5 ) 80OutlineCircularBuffer Test.java(4 of 5 ) 81OutlineCircularBuffer Test.java(5 of 5 ) 8223.10 Producer/Consumer Relationship: The Lock and Condition InterfacesIntroduced in Java SE 5Give programmers more precise control over thread synchronization, but are more complicated to useAny object can contain a reference to an object that implements the Lock interface (of package java.util.concurrent.locks)Call Lock’s lock method to acquire the lockOnce obtained by one thread, the Lock object will not allow another thread to obtain the Lock until the first thread releases the Lock Call Lock’s unlock method to release the lockAll other threads attempting to obtain that Lock on a locked object are placed in the waiting state8323.10 Producer/Consumer Relationship: The Lock and Condition InterfacesClass ReentrantLock (of package java.util.concurrent.locks) is a basic implementation of the Lock interface. ReentrantLock constructor takes a boolean argument that specifies whether the lock has a fairness policyIf true, the ReentrantLock’s fairness policy is “the longest-waiting thread will acquire the lock when it is available”—prevents starvation If false, there is no guarantee as to which waiting thread will acquire the lock when it is availableA thread that owns a Lock and determines that it cannot continue with its task until some condition is satisfied can wait on a condition objectLock objects allow you to explicitly declare the condition objects on which a thread may need to wait8423.10 Producer/Consumer Relationship: The Lock and Condition InterfacesCondition objects Associated with a specific Lock Created by calling a Lock’s newCondition methodTo wait on a Condition object, call the Condition ’s await methodimmediately releases the associated Lock and places the thread in the waiting state for that Condition Another thread can call Condition method signal to allow a thread in that Condition’s waiting state to return to the runnable stateDefault implementation of Condition signals the longest-waiting threadCondition method signalAll transitions all the threads waiting for that condition to the runnable stateWhen finished with a shared object, thread must call unlock to release the Lock8523.10 Producer/Consumer Relationship: The Lock and Condition InterfacesLock and Condition may be preferable to using the synchronized keywordLock objects allow you to interrupt waiting threads or to specify a timeout for waiting to acquire a lockLock object is not constrained to be acquired and released in the same block of codeCondition objects can be used to specify multiple conditions on which threads may waitPossible to indicate to waiting threads that a specific condition object is now true86Software Engineering Observation 23.2Using a ReentrantLock with a fairness policy avoids indefinite postponement.87Performance Tip 23.4Using a ReentrantLock with a fairness policy can decrease program performance significantly. 88Common Programming Error 23.2Deadlock occurs when a waiting thread (let us call this thread1) cannot proceed because it is waiting (either directly or indirectly) for another thread (let us call this thread2) to proceed, while simultaneously thread2 cannot proceed because it is waiting (either directly or indirectly) for thread1 to proceed. The two threads are waiting for each other, so the actions that would enable each thread to continue execution can never occur.89Error-Prevention Tip 23.3When multiple threads manipulate a shared object using locks, ensure that if one thread calls method await to enter the waiting state for a condition object, a separate thread eventually will call Condition method signal to transition the thread waiting on the condition object back to the runnable state. If multiple threads may be waiting on the condition object, a separate thread can call Condition method signalAll as a safeguard to ensure that all the waiting threads have another opportunity to perform their tasks. If this is not done, starvation might occur.90Common Programming Error 23.3An IllegalMonitorStateException occurs if a thread issues an await, a signal, or a signalAll on a condition object without having acquired the lock for that condition object.91OutlineSynchronized Buffer.java(1 of 4 ) Synchronized implementation of interface Buffer that uses Locks and ConditionsCondition indicating when a producer can writeCondition indicating when a consumer can readManually acquire the lock to implement mutual exclusion92OutlineSynchronized Buffer.java(2 of 4 ) Producer must wait until buffer is empty and release the lockProducer signals the consumer that a value is available for readingRelease the lock so consumer can read93OutlineSynchronized Buffer.java(3 of 4 ) Manually acquire the lock to implement mutual exclusionConsumer must wait until buffer is full and release the lockConsumer signals the producer that space is available for writing94OutlineSynchronized Buffer.java(4 of 4 ) Release the lock so producer can write95Error-Prevention Tip 23.4 Place calls to Lock method unlock in a finally block. If an exception is thrown, unlock must still be called or deadlock could occur.96Common Programming Error 23.4Forgetting to signal a waiting thread is a logic error. The thread will remain in the waiting state, which will prevent the thread from proceeding. Such waiting can lead to indefinite postponement or deadlock.97OutlineSharedBuffer Test2.java(1 of 3 ) 98OutlineSharedBuffer Test2.java(2 of 3 ) 99OutlineSharedBuffer Test2.java(3 of 3 ) 10023.11 Multithreading with GUIEvent dispatch thread handles interactions with the application’s GUI componentsAll tasks that interact with an application’s GUI are placed in an event queueExecuted sequentially by the event dispatch threadSwing GUI components are not thread safeThread safety achieved by ensuring that Swing components are accessed from only the event dispatch thread—known as thread confinementPreferable to handle long-running computations in a separate thread, so the event dispatch thread can continue managing other GUI interactionsClass SwingWorker (in package javax.swing) implements interface Runnable Performs long-running computations in a worker threadUpdates Swing components from the event dispatch thread based on the computations’ results 101Fig. 23.24 | Commonly used SwingWorker methods.10223.11.1 Performing Computations in a Worker ThreadTo use a SwingWorkerExtend SwingWorkerOverrides methods doInBackground and donedoInBackground performs the computation and returns the result done displays the results in the GUI after doInBackground returnsSwingWorker is a generic classFirst type parameter indicates the type returned by doInBackground Second indicates the type passed between the publish and process methods to handle intermediate resultsExecutionException thrown if an exception occurs during the computation103OutlineBackground Calculator.java(1 of 2 ) Create a subclass of SwingWorker to Possibly lengthy Fibonacci calculation to perform in the background104OutlineBackground Calculator.java(2 of 2 ) Display the calculation results when done105Software Engineering Observation 23.3 Any GUI components that will be manipulated by SwingWorker methods, such as components that will be updated from methods process or done, should be passed to the SwingWorker subclass’s constructor and stored in the subclass object. This gives these methods access to the GUI components they will manipulate.106OutlineFibonacciNumbers.java(1 of 5 ) 107OutlineFibonacciNumbers.java(2 of 5 ) 108OutlineFibonacciNumbers.java(3 of 5 ) 109OutlineFibonacciNumbers.java(4 of 5 ) 110OutlineFibonacciNumbers.java(5 of 5 ) 11123.11.2 Processing Intermediate Results with SwingWorkerSwingWorker methodspublish repeatedly sends intermediate results to method processprocess executes in the event dispatch thread and receives data from method publish then displays the data in a GUI componentsetProgress updates the progress propertyValues are passed asynchronously between publish in the worker thread and process in the event dispatch thread process is not necessarily invoked for every call to publishPropertyChangeListener Interface from package java.beans Defines method propertyChangeEach call to setProgress generates a PropertyChangeEvent to indicate that the progress property has changed 112OutlinePrimeCalculator .java(1 of 5 ) 113OutlinePrimeCalculator .java(2 of 5 ) Specify progress status as a percentage of the number of primes we are calculating114OutlinePrimeCalculator .java(3 of 5 ) Publish each prime as it is discoveredProcess all the published prime values115OutlinePrimeCalculator .java(4 of 5 ) 116OutlinePrimeCalculator .java(5 of 5 ) 117OutlineFindPrimes.java(1 of 6 ) 118OutlineFindPrimes.java(2 of 6 ) 119OutlineFindPrimes.java(3 of 6 ) 120OutlineFindPrimes.java(4 of 6 ) 121OutlineFindPrimes.java(5 of 6 ) 122OutlineFindPrimes.java(6 of 6 ) 12323.12 Other Classes and Interfaces in java.util.concurrentCallable interface package java.util.concurrentdeclares a single method named callsimilar to Runnable, but method call allows the thread to return a value or to throw a checked exceptionExecutorService method submit executes a CallableReturns an object of type Future (of package java.util.concurrent) that represents the executing CallableFuture declares method get to return the result of the Callable and other methods to manage a Callable’s execution124
Các file đính kèm theo tài liệu này:
- javahtp7e_23_0829_9802.ppt