1.Without concurrency, the only way to produce a responsive user interface is for all tasks to periodically check for user input. By creating a separate thread of execution to respond to user input, even though this thread will be blocked most of the time, the program guarantees a certain level of responsiveness.
2.In general, threads enable you to create a more loosely coupled design; otherwise, parts of your code would be forced to pay explicit attention to tasks that would normally be handled by threads.
3.The call to the static method Thread.yield( ) inside run( ) is a suggestion to the thread scheduler (the part of the Java threading mechanism that moves the CPU from one thread to the next) that says, "I’ve done the important parts of my cycle and this would be a good time to switch to another task for a while.
4.When a class is derived from Runnable, it must have a run( ) method, but that’s nothing special—it doesn’t produce any innate threading abilities. To achieve threading behavior, you must explicitly attach a task to a thread.
5.The traditional way to turn a Runnable object into a working task is to hand it to a Thread constructor.
6.
public class BasicThreads { public static void main(String[] args) { Thread t = new Thread(new LiftOff()); t.start(); System.out.println("Waiting for LiftOff"); } }
A Thread constructor only needs a Runnable object. Calling a Thread object’s start( ) will perform the necessary initialization for the thread and then call that Runnable’s run( ) method to start the task in the new thread. Even though start( ) appears to be making a call to a long-running method, you can see from the output—the "Waiting for LiftOff’ message appears before the countdown has completed—that start( ) quickly returns. In effect, you have made a method call to LiftOff.run( ), and that method has not yet finished, but because LiftOff.run( ) is being executed by a different thread, you can still perform other operations in the main( ) thread.
7.The output for one run of this program will be different from that of another, because the thread-scheduling mechanism is not deterministic.
8.When main( ) creates the Thread objects, it isn’t capturing the references for any of them. Each Thread "registers" itself so there is actually a reference to it someplace, and the garbage collector can’t clean it up until the task exits its run( ) and dies. You can see from the output that the tasks are indeed running to conclusion, so a thread creates a separate thread of execution that persists after the call to start( ) completes.
9.Executors provide a layer of indirection between a client and the execution of a task; instead of a client executing a task directly, an intermediate object executes the task. Executors allow you to manage the execution of asynchronous tasks without having to explicitly manage the lifecycle of threads.
An ExecutorService knows how to build the appropriate context to execute Runnable objects. The CachedThreadPool creates one thread per task. Note that an ExecutorService object is created using a static Executors method which determines the kind of Executor it will be.
Very often, a single Executor can be used to create and manage all the tasks in your system.The call to shutdown( ) prevents new tasks from being submitted to that Executor.The current thread will continue to run all tasks submitted before shutdown( ) was called. The program will exit as soon as all the tasks in the Executor finish.
10.A FixedThreadPool uses a limited set of threads to execute the submitted tasks.(如果限制小于execute()调用的次数,并不会报错终止,而是一次执行限制数目的线程,等第一次执行的线程都结束后,再开启剩余的线程,如果剩余的还是大于限制,第二次仍然开启限制数目的线程,以此类推)
For example
ExecutorService exec = Executors.newFixedThreadPool(5); for (int i = 0; i < 5; i++) exec.execute(new LiftOff()); exec.shutdown();
则先#0 #1,然后#2 #3 最后#4,一次开2个线程
With the FixedThreadPool, you do expensive thread allocation once, up front, and you thus limit the number of threads. This saves time because you aren’t constantly paying for thread creation overhead for every single task. Also, in an event-driven system, event handlers that require threads can be serviced as quickly as you want by simply fetching threads from the pool. You don’t overrun the available resources because the FixedThreadPool uses a bounded number of Thread objects.
11.In any of the thread pools, existing threads are automatically reused when possible.It's a reasonable first choice as an Executor. Only if this approach causes problems do you need to switch to a FixedThreadPool.
12.A SingleThreadExecutor is like a FixedThreadPool with a size of one thread.
As an example, suppose you have a number of threads running tasks that use the file system. You can run these tasks with a SingleThreadExecutor to ensure that only one task at a time is running from any thread.Sometimes a better solution is to synchronize on the resource , but a SingleThreadExecutor lets you skip the trouble of getting coordinated properly just to prototype something.