Thinking in Java 4th Edition phần 9 potx

108 478 0
Thinking in Java 4th Edition phần 9 potx

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

Thông tin tài liệu

 Exercise 15: (1) Create a class with three methods containing critical sections that all synchronize on the same object. Create multiple tasks to demonstrate that only one of these methods can run at a time. Now modify the methods so that each one synchronizes on a different object and show that all three methods can be running at once. Exercise 16: (1) Modify Exercise 15 to use explicit Lock objects. Thread local storage A second way to prevent tasks from colliding over shared resources is to eliminate the sharing of variables. Thread local storage is a mechanism that automatically creates different storage for the same variable, for each different thread that uses an object. Thus, if you have five threads using an object with a variable x, thread local storage generates five different pieces of storage for x. Basically, they allow you to associate state with a thread. The creation and management of thread local storage is taken care of by the java.lang.ThreadLocal class, as seen here: //: concurrency/ThreadLocalVariableHolder.java // Automatically giving each thread its own storage. import java.util.concurrent.*; import java.util.*; class Accessor implements Runnable { private final int id; public Accessor(int idn) { id = idn; } public void run() { while(!Thread.currentThread().isInterrupted()) { ThreadLocalVariableHolder.increment(); System.out.println(this); Thread.yield(); } } public String toString() { return "#" + id + ": " + ThreadLocalVariableHolder.get(); } } public class ThreadLocalVariableHolder { private static ThreadLocal<Integer> value = new ThreadLocal<Integer>() { private Random rand = new Random(47); protected synchronized Integer initialValue() { return rand.nextInt(10000); } }; public static void increment() { value.set(value.get() + 1); } public static int get() { return value.get(); } public static void main(String[] args) throws Exception { ExecutorService exec = Executors.newCachedThreadPool(); for(int i = 0; i < 5; i++) exec.execute(new Accessor(i)); TimeUnit.SECONDS.sleep(3); // Run for a while exec.shutdownNow(); // All Accessors will quit } } /* Output: (Sample) #0: 9259 Concurrency 843 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com  #1: 556 #2: 6694 #3: 1862 #4: 962 #0: 9260 #1: 557 #2: 6695 #3: 1863 #4: 963 *///:~ ThreadLocal objects are usually stored as static fields. When you create a ThreadLocal object, you are only able to access the contents of the object using the get( ) and set( ) methods. The get( ) method returns a copy of the object that is associated with that thread, and set( ) inserts its argument into the object stored for that thread, returning the old object that was in storage. The increment( ) and get( ) methods demonstrate this in ThreadLocalVariableHolder. Notice that increment( ) and get( ) are not synchronized, because ThreadLocal guarantees that no race condition can occur. When you run this program, you’ll see evidence that the individual threads are each allocated their own storage, since each one keeps its own count even though there’s only one ThreadLocalVariableHolder object. Terminating tasks In some of the previous examples, cancel( ) and isCanceled( ) methods are placed in a class that is seen by all tasks. The tasks check isCanceled( ) to determine when to terminate themselves. This is a reasonable approach to the problem. However, in some situations the task must be terminated more abruptly. In this section, you’ll learn about the issues and problems of such termination. First, let’s look at an example that not only demonstrates the termination problem but also is an additional example of resource sharing. The ornamental garden In this simulation, the garden committee would like to know how many people enter the garden each day through its multiple gates. Each gate has a turnstile or some other kind of counter, and after the turnstile count is incremented, a shared count is incremented that represents the total number of people in the garden. //: concurrency/OrnamentalGarden.java import java.util.concurrent.*; import java.util.*; import static net.mindview.util.Print.*; class Count { private int count = 0; private Random rand = new Random(47); // Remove the synchronized keyword to see counting fail: public synchronized int increment() { int temp = count; if(rand.nextBoolean()) // Yield half the time Thread.yield(); return (count = ++temp); } 844 Thinking in Java Bruce Eckel Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com  public synchronized int value() { return count; } } class Entrance implements Runnable { private static Count count = new Count(); private static List<Entrance> entrances = new ArrayList<Entrance>(); private int number = 0; // Doesn’t need synchronization to read: private final int id; private static volatile boolean canceled = false; // Atomic operation on a volatile field: public static void cancel() { canceled = true; } public Entrance(int id) { this.id = id; // Keep this task in a list. Also prevents // garbage collection of dead tasks: entrances.add(this); } public void run() { while(!canceled) { synchronized(this) { ++number; } print(this + " Total: " + count.increment()); try { TimeUnit.MILLISECONDS.sleep(100); } catch(InterruptedException e) { print("sleep interrupted"); } } print("Stopping " + this); } public synchronized int getValue() { return number; } public String toString() { return "Entrance " + id + ": " + getValue(); } public static int getTotalCount() { return count.value(); } public static int sumEntrances() { int sum = 0; for(Entrance entrance : entrances) sum += entrance.getValue(); return sum; } } public class OrnamentalGarden { public static void main(String[] args) throws Exception { ExecutorService exec = Executors.newCachedThreadPool(); for(int i = 0; i < 5; i++) exec.execute(new Entrance(i)); // Run for a while, then stop and collect the data: TimeUnit.SECONDS.sleep(3); Entrance.cancel(); exec.shutdown(); if(!exec.awaitTermination(250, TimeUnit.MILLISECONDS)) print("Some tasks were not terminated!"); print("Total: " + Entrance.getTotalCount()); print("Sum of Entrances: " + Entrance.sumEntrances()); } } /* Output: (Sample) Concurrency 845 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com  Entrance 0: 1 Total: 1 Entrance 2: 1 Total: 3 Entrance 1: 1 Total: 2 Entrance 4: 1 Total: 5 Entrance 3: 1 Total: 4 Entrance 2: 2 Total: 6 Entrance 4: 2 Total: 7 Entrance 0: 2 Total: 8 Entrance 3: 29 Total: 143 Entrance 0: 29 Total: 144 Entrance 4: 29 Total: 145 Entrance 2: 30 Total: 147 Entrance 1: 30 Total: 146 Entrance 0: 30 Total: 149 Entrance 3: 30 Total: 148 Entrance 4: 30 Total: 150 Stopping Entrance 2: 30 Stopping Entrance 1: 30 Stopping Entrance 0: 30 Stopping Entrance 3: 30 Stopping Entrance 4: 30 Total: 150 Sum of Entrances: 150 *///:~ A single Count object keeps the master count of garden visitors, and is stored as a static field in the Entrance class. Count.increment( ) and Count.value( ) are synchronized to control access to the count field. The increment( ) method uses a Random object to cause a yield( ) roughly half the time, in between fetching count into temp and incrementing and storing temp back into count. If you comment out the synchronized keyword on increment( ), the program breaks because multiple tasks will be accessing and modifying count simultaneously (the yield( ) causes the problem to happen more quickly). Each Entrance task keeps a local value number containing the number of visitors that have passed through that particular entrance. This provides a double check against the count object to make sure that the proper number of visitors is being recorded. Entrance.run( ) simply increments number and the count object and sleeps for 100 milliseconds. Because Entrance.canceled is a volatile boolean flag which is only read and assigned (and is never read in combination with other fields), it’s possible to get away without synchronizing access to it. If you have any doubts about something like this, it’s always better to use synchronized. This program goes to quite a bit of extra trouble to shut everything down in a stable fashion. Part of the reason for this is to show just how careful you must be when terminating a multithreaded program, and part of the reason is to demonstrate the value of interrupt( ), which you will learn about shortly. After 3 seconds, main( ) sends the static cancel( ) message to Entrance, then calls shutdown( ) for the exec object, and then calls awaitTermination( ) on exec. ExecutorService.awaitTermination( ) waits for each task to complete, and if they all complete before the timeout value, it returns true, otherwise it returns false to indicate that not all tasks have completed. Although this causes each task to exit its run( ) method and therefore terminate as a task, the Entrance objects are still valid because, in the constructor, each Entrance object is stored in a static List<Entrance> called entrances. Thus, sumEntrances( ) is still working with valid Entrance objects. 846 Thinking in Java Bruce Eckel Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com  As this program runs, you will see the total count and the count at each entrance displayed as people walk through a turnstile. If you remove the synchronized declaration on Count.increment( ), you’ll notice that the total number of people is not what you expect it to be. The number of people counted by each turnstile will be different from the value in count. As long as the mutex is there to synchronize access to the Count, things work correctly. Keep in mind that Count.increment( ) exaggerates the potential for failure by using temp and yield( ). In real threading problems, the possibility for failure may be statistically small, so you can easily fall into the trap of believing that things are working correctly. Just as in the example above, there are likely to be hidden problems that haven’t occurred to you, so be exceptionally diligent when reviewing concurrent code. Exercise 17: (2) Create a radiation counter that can have any number of remote sensors. Terminating when blocked Entrance.run( ) in the previous example includes a call to sleep( ) in its loop. We know that sleep( ) will eventually wake up and the task will reach the top of the loop, where it has an opportunity to break out of that loop by checking the cancelled flag. However, sleep( ) is just one situation where a task is blocked from executing, and sometimes you must terminate a task that’s blocked. Thread states A thread can be in any one of four states: 1. New: A thread remains in this state only momentarily, as it is being created. It allocates any necessary system resources and performs initialization. At this point it becomes eligible to receive CPU time. The scheduler will then transition this thread to the runnable or blocked state. 2. Runnable: This means that a thread can be run when the time-slicing mechanism has CPU cycles available for the thread. Thus, the thread might or might not be running at any moment, but there’s nothing to prevent it from being run if the scheduler can arrange it. That is, it’s not dead or blocked. 3. Blocked: The thread can be run, but something prevents it. While a thread is in the blocked state, the scheduler will simply skip it and not give it any CPU time. Until a thread reenters the runnable state, it won’t perform any operations. 4. Dead: A thread in the dead or terminated state is no longer schedulable and will not receive any CPU time. Its task is completed, and it is no longer runnable. One way for a task to die is by returning from its run( ) method, but a task’s thread can also be interrupted, as you’ll see shortly. Becoming blocked A task can become blocked for the following reasons: • You’ve put the task to sleep by calling sleep(milliseconds), in which case it will not be run for the specified time. • You’ve suspended the execution of the thread with wait( ). It will not become runnable again until the thread gets the notify( ) or notifyAll( ) message (or the equivalent signal( ) or signalAll( ) for the Java SE5 java.util.concurrent library tools). We’ll examine these in a later section. Concurrency 847 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com  848 Thinking in Java Bruce Eckel • The task is waiting for some I/O to complete. • The task is trying to call a synchronized method on another object, and that object’s lock is not available because it has already been acquired by another task. In old code, you may also see suspend( ) and resume( ) used to block and unblock threads, but these are deprecated in modern Java (because they are deadlock-prone), and so will not be examined in this book. The stop( ) method is also deprecated, because it doesn’t release the locks that the thread has acquired, and if the objects are in an inconsistent state ("damaged"), other tasks can view and modify them in that state. The resulting problems can be subtle and difficult to detect. The problem we need to look at now is this: Sometimes you want to terminate a task that is in a blocked state. If you can’t wait for it to get to a point in the code where it can check a state value and decide to terminate on its own, you have to force the task out of its blocked state. Interruption As you might imagine, it’s much messier to break out of the middle of a Runnable.run( ) method than it is to wait for that method to get to a test of a "cancel" flag, or to some other place where the programmer is ready to leave the method. When you break out of a blocked task, you might need to clean up resources. Because of this, breaking out of the middle of a task’s run( ) is more like throwing an exception than anything else, so in Java threads, exceptions are used for this kind of abort. 16 (This walks the fine edge of being an inappropriate use of exceptions, because it means you are often using them for control flow.) To return to a known good state when terminating a task this way, you must carefully consider the execution paths of your code and write your catch clause to properly clean everything up. So that you can terminate a blocked task, the Thread class contains the interrupt( ) method. This sets the interrupted status for that thread. A thread with its interrupted status set will throw an InterruptedException if it is already blocked or if it attempts a blocking operation. The interrupted status will be reset when the exception is thrown or if the task calls Thread.interrupted( ). As you’ll see, Thread.interrupted( ) provides a second way to leave your run( ) loop, without throwing an exception. To call interrupt( ), you must hold a Thread object. You may have noticed that the new concurrent library seems to avoid the direct manipulation of Thread objects and instead tries to do everything through Executors. If you call shutdownNow( ) on an Executor, it will send an interrupt( ) call to each of the threads it has started. This makes sense because you’ll usually want to shut down all the tasks for a particular Executor at once, when you’ve finished part of a project or a whole program. However, there are times when you may want to only interrupt a single task. If you’re using Executors, you can hold on to the context of a task when you start it by calling submit( ) instead of execute( ). submit( ) returns a generic Future<?>, with an unspecified parameter because you won’t ever call get( ) on it— the point of holding this kind of Future is that you can call cancel( ) on it and thus use it to interrupt a particular task. If you pass true to cancel( ), it has permission to call interrupt( ) on that thread in order to stop it; thus cancel( ) is a way to interrupt individual threads started with an Executor. Here’s an example that shows the basics of interrupt( ) using Executors: //: concurrency/Interrupting.java  16 However, exceptions are never delivered asynchronously. Thus, there is no danger of something aborting mid- instruction/method call. And as long as you use the try-finally idiom when using object mutexes (vs. the synchronized keyword), those mutexes will be automatically released if an exception is thrown. Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com  // Interrupting a blocked thread. import java.util.concurrent.*; import java.io.*; import static net.mindview.util.Print.*; class SleepBlocked implements Runnable { public void run() { try { TimeUnit.SECONDS.sleep(100); } catch(InterruptedException e) { print("InterruptedException"); } print("Exiting SleepBlocked.run()"); } } class IOBlocked implements Runnable { private InputStream in; public IOBlocked(InputStream is) { in = is; } public void run() { try { print("Waiting for read():"); in.read(); } catch(IOException e) { if(Thread.currentThread().isInterrupted()) { print("Interrupted from blocked I/O"); } else { throw new RuntimeException(e); } } print("Exiting IOBlocked.run()"); } } class SynchronizedBlocked implements Runnable { public synchronized void f() { while(true) // Never releases lock Thread.yield(); } public SynchronizedBlocked() { new Thread() { public void run() { f(); // Lock acquired by this thread } }.start(); } public void run() { print("Trying to call f()"); f(); print("Exiting SynchronizedBlocked.run()"); } } public class Interrupting { private static ExecutorService exec = Executors.newCachedThreadPool(); static void test(Runnable r) throws InterruptedException{ Future<?> f = exec.submit(r); TimeUnit.MILLISECONDS.sleep(100); print("Interrupting " + r.getClass().getName()); f.cancel(true); // Interrupts if running print("Interrupt sent to " + r.getClass().getName()); } Concurrency 849 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com  850 Thinking in Java Bruce Eckel public static void main(String[] args) throws Exception { test(new SleepBlocked()); test(new IOBlocked(System.in)); test(new SynchronizedBlocked()); TimeUnit.SECONDS.sleep(3); print("Aborting with System.exit(0)"); System.exit(0); // since last 2 interrupts failed } } /* Output: (95% match) Interrupting SleepBlocked InterruptedException Exiting SleepBlocked.run() Interrupt sent to SleepBlocked Waiting for read(): Interrupting IOBlocked Interrupt sent to IOBlocked Trying to call f() Interrupting SynchronizedBlocked Interrupt sent to SynchronizedBlocked Aborting with System.exit(0) *///:~ Each task represents a different kind of blocking. SleepBlock is an example of interruptible blocking, whereas IOBlocked and SynchronizedBlocked are uninterruptible blocking. 17 The program proves that I/O and waiting on a synchronized lock are not interruptible, but you can also anticipate this by looking at the code—no InterruptedException handler is required for either I/O or attempting to call a synchronized method. The first two classes are straightforward: The run( ) method calls sleep( ) in the first class and read( ) in the second. To demonstrate SynchronizedBlocked, however, we must first acquire the lock. This is accomplished in the constructor by creating an instance of an anonymous Thread class that acquires the object lock by calling f( ) (the thread must be different from the one driving run( ) for SynchronizedBlock because one thread can acquire an object lock multiple times). Since f( ) never returns, that lock is never released. SynchronizedBlock.run( ) attempts to call f( ) and is blocked waiting for the lock to be released. You’ll see from the output that you can interrupt a call to sleep( ) (or any call that requires you to catch InterruptedException). However, you cannot interrupt a task that is trying to acquire a synchronized lock or one that is trying to perform I/O. This is a little disconcerting, especially if you’re creating a task that performs I/O, because it means that I/O has the potential of locking your multithreaded program. Especially for Web-based programs, this is a concern. A heavy-handed but sometimes effective solution to this problem is to close the underlying resource on which the task is blocked: //: concurrency/CloseResource.java // Interrupting a blocked task by // closing the underlying resource. // {RunByHand} import java.net.*; import java.util.concurrent.*; import java.io.*; import static net.mindview.util.Print.*;  17 Some releases of the JDK also provided support for InterruptedIOException. However, this was only partially implemented, and only on some platforms. If this exception is thrown, it causes 10 objects to be unusable. Future releases are unlikely to continue support for this exception. Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com  public class CloseResource { public static void main(String[] args) throws Exception { ExecutorService exec = Executors.newCachedThreadPool(); ServerSocket server = new ServerSocket(8080); InputStream socketInput = new Socket("localhost", 8080).getInputStream(); exec.execute(new IOBlocked(socketInput)); exec.execute(new IOBlocked(System.in)); TimeUnit.MILLISECONDS.sleep(100); print("Shutting down all threads"); exec.shutdownNow(); TimeUnit.SECONDS.sleep(1); print("Closing " + socketInput.getClass().getName()); socketInput.close(); // Releases blocked thread TimeUnit.SECONDS.sleep(1); print("Closing " + System.in.getClass().getName()); System.in.close(); // Releases blocked thread } } /* Output: (85% match) Waiting for read(): Waiting for read(): Shutting down all threads Closing java.net.SocketInputStream Interrupted from blocked I/O Exiting IOBlocked.run() Closing java.io.BufferedInputStream Exiting IOBlocked.run() *///:~ After shutdownNow( ) is called, the delays before calling close( ) on the two input streams emphasize that the tasks unblock once the underlying resource is closed. It’s interesting to note that the interrupt( ) appears when you are closing the Socket but not when closing System.in. Fortunately, the nio classes introduced in the I/O chapter provide for more civilized interruption of I/O. Blocked nio channels automatically respond to interrupts: //: concurrency/NIOInterruption.java // Interrupting a blocked NIO channel. import java.net.*; import java.nio.*; import java.nio.channels.*; import java.util.concurrent.*; import java.io.*; import static net.mindview.util.Print.*; class NIOBlocked implements Runnable { private final SocketChannel sc; public NIOBlocked(SocketChannel sc) { this.sc = sc; } public void run() { try { print("Waiting for read() in " + this); sc.read(ByteBuffer.allocate(1)); } catch(ClosedByInterruptException e) { print("ClosedByInterruptException"); } catch(AsynchronousCloseException e) { print("AsynchronousCloseException"); } catch(IOException e) { throw new RuntimeException(e); } print("Exiting NIOBlocked.run() " + this); } Concurrency 851 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com  852 Thinking in Java Bruce Eckel } public class NIOInterruption { public static void main(String[] args) throws Exception { ExecutorService exec = Executors.newCachedThreadPool(); ServerSocket server = new ServerSocket(8080); InetSocketAddress isa = new InetSocketAddress("localhost", 8080); SocketChannel sc1 = SocketChannel.open(isa); SocketChannel sc2 = SocketChannel.open(isa); Future<?> f = exec.submit(new NIOBlocked(sc1)); exec.execute(new NIOBlocked(sc2)); exec.shutdown(); TimeUnit.SECONDS.sleep(1); // Produce an interrupt via cancel: f.cancel(true); TimeUnit.SECONDS.sleep(1); // Release the block by closing the channel: sc2.close(); } } /* Output: (Sample) Waiting for read() in NIOBlocked@7a84e4 Waiting for read() in NIOBlocked@15c7850 ClosedByInterruptException Exiting NIOBlocked.run() NIOBlocked@15c7850 AsynchronousCloseException Exiting NIOBlocked.run() NIOBlocked@7a84e4 *///:~ As shown, you can also close the underlying channel to release the block, although this should rarely be necessary. Note that using execute( ) to start both tasks and calling e.shutdownNow( ) will easily terminate everything; capturing the Future in the example above was only necessary to send the interrupt to one thread and not the other. 18 Exercise 18: (2) Create a non-task class with a method that calls sleep( ) for a long interval. Create a task that calls the method in the non-task class. In main( ), start the task, then call interrupt( ) to terminate it. Make sure that the task shuts down safely. Exercise 19: (4) Modify OrnamentalGarden.java so that it uses interrupt( ). Exercise 20: (1) Modify CachedThreadPool.java so that all tasks receive an interrupt( ) before they are completed. Blocked by a mutex As you saw in Interrupting.java, if you try to call a synchronized method on an object whose lock has already been acquired, the calling task will be suspended (blocked) until the lock becomes available. The following example shows how the same mutex can be multiply acquired by the same task: //: concurrency/MultiLock.java // One thread can reacquire the same lock. import static net.mindview.util.Print.*; public class MultiLock { public synchronized void f1(int count) { if(count > 0) {  18 Ervin Varga helped research this section. Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com [...]... of n2: try { print("Calculating"); // A time-consuming, non-blocking operation: for(int i = 1; i < 2500000; i++) d = d + (Math.PI + Math.E) / d; print("Finished time-consuming operation"); } finally { n2.cleanup(); } } finally { n1.cleanup(); } } print("Exiting via while() test"); } catch(InterruptedException e) { print("Exiting via InterruptedException"); } } } public class InterruptingIdiom { public... call to blocked.f( ) Thinking in Java Bruce Eckel   Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com //: concurrency/InterruptingIdiom .java // General idiom for interrupting a task // {Args: 1100} import java. util.concurrent.*; import static net.mindview.util.Print.*; class NeedsCleanup { private final int id; public NeedsCleanup(int ident) { id = ident; print("NeedsCleanup "... run() { print("Waiting for f() in BlockedMutex"); blocked.f(); print("Broken out of blocked call"); } } public class Interrupting2 { public static void main(String[] args) throws Exception { Thread t = new Thread(new Blocked2()); t.start(); TimeUnit.SECONDS.sleep(1); System.out.println("Issuing t.interrupt()"); t.interrupt(); } } /* Output: Waiting for f() in BlockedMutex Issuing t.interrupt() Interrupted... basically a blocking queue, which existed in versions of Java before BlockingQueue was introduced Here’s a simple example in which two tasks use a pipe to communicate: //: concurrency/PipedIO .java // Using pipes for inter-task I/O import java. util.concurrent.*; 872 Thinking in Java Bruce Eckel   Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com import java. io.*; import java. util.*;... details): //: concurrency/FixedDiningPhilosophers .java // Dining philosophers without deadlock // {Args: 5 5 timeout} import java. util.concurrent.*; public class FixedDiningPhilosophers { public static void main(String[] args) throws Exception { int ponder = 5; if(args.length > 0) ponder = Integer.parseInt(args[0]); int size = 5; if(args.length > 1) size = Integer.parseInt(args[1]); ExecutorService exec... car.waitForBuffing(); } } catch(InterruptedException e) { print("Exiting via interrupt"); } print("Ending Wax On task"); } } class WaxOff implements Runnable { 858 Thinking in Java Bruce Eckel   Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com } private Car car; public WaxOff(Car c) { car = c; } public void run() { try { while(!Thread.interrupted()) { car.waitForWaxing(); printnb("Wax Off!... Thread[pool-1-thread2,5,main] Thread[pool-1-thread-3,5,main] Thread[pool-1-thread-4,5,main] Thread[pool-1-thread-5,5,main] 862 Thinking in Java Bruce Eckel   Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com notify() Thread[pool-1-thread-1,5,main] notifyAll() Thread[pool-1-thread-1,5,main] Thread[pool-1-thread5,5,main] Thread[pool-1-thread-4,5,main] Thread[pool-1-thread-3,5,main] Thread[pool-1-thread-2,5,main]... car.waitForBuffing(); } } catch(InterruptedException e) { print("Exiting via interrupt"); } print("Ending Wax On task"); } } class WaxOff implements Runnable { private Car car; public WaxOff(Car c) { car = c; } public void run() { try { while(!Thread.interrupted()) { car.waitForWaxing(); printnb("Wax Off! "); TimeUnit.MILLISECONDS.sleep(200); car.buffed(); } } catch(InterruptedException e) { print("Exiting via interrupt");... catch(InterruptedException e) { print("Interrupted during put()"); } } public void run() { try { while(!Thread.interrupted()) { LiftOff rocket = rockets.take(); rocket.run(); // Use this thread } } catch(InterruptedException e) { print("Waking from take()"); } print("Exiting LiftOffRunner"); } } public class TestBlockingQueues { static void getkey() { try { // Compensate for Windows/Linux difference in. .. on the BlockingQueue by main( ) and are taken off the BlockingQueue by the LiftOffRunner Notice that LiftOffRunner can ignore synchronization issues because they are solved by the BlockingQueue Exercise 28: (3) Modify TestBlockingQueues .java by adding a new task that places LiftOff on the BlockingQueue, instead of doing it in main( ) BlockingQueues of toast As an example of the use of BlockingQueues, . Exiting via interrupt Ending Wax On task Exiting via interrupt Ending Wax Off task *///:~ Here, Car has a single boolean waxOn, which indicates the state of the waxing-polishing process. In. System.out.println("Issuing t.interrupt()"); t.interrupt(); } } /* Output: Waiting for f() in BlockedMutex Issuing t.interrupt() Interrupted from lock acquisition in f() Broken. System.exit(0); // since last 2 interrupts failed } } /* Output: (95 % match) Interrupting SleepBlocked InterruptedException Exiting SleepBlocked.run() Interrupt sent to SleepBlocked Waiting for read():

Ngày đăng: 14/08/2014, 00:21

Từ khóa liên quan

Mục lục

  • Thinking in Java

  • Content

Tài liệu cùng người dùng

  • Đang cập nhật ...

Tài liệu liên quan