1. Java Multithreading Program design in layman 's
Multithreading is a mechanism that allows multiple instruction flows to be executed concurrently in a program, each of which is called a thread and is independent of each other.
One: Understanding Multithreading
Multithreading is a mechanism that allows multiple instruction flows to be executed concurrently in a program, each of which is called a multithreaded mechanism that allows multiple instruction flows to be executed concurrently in a program, each of which is called a thread, also known as a lightweight process, and has independent execution control as a process. The operating system is responsible for scheduling, the difference is that the thread does not have independent storage space, but rather with the other threads in the process to share a storage space, which makes communication between threads far simpler than the process.
The execution of multiple threads is concurrent, that is, logically "simultaneous", regardless of whether it is physically "simultaneous". If the system has only one CPU, then the real "at the same time" is not possible, but because the CPU speed is very fast, the user does not feel the difference, so we do not care about it, only need to imagine that each thread is executed at the same time.
Multi-threaded and traditional single-threaded in the biggest difference in program design, because each thread control flow independent of each other, so that the code between the various threads is executed in a disorderly sequence, resulting in thread scheduling, synchronization and other issues, will be discussed later.
Two: Multithreading in Java
We might as well imagine what we need to do in order to create a new thread. Obviously, we have to point out the code that this thread is going to execute, and that's what we need to do in Java to implement multithreading!
It's amazing! How does Java do that? Through the Class! As a fully object-oriented language, Java provides class Java.lang.Thread to facilitate multithreaded programming, a class that provides a number of ways to make it easier for us to control our own threads, and future discussions will revolve around this class.
So how do we give Java the code we want the thread to execute? Let's take a look at the Thread class. The most important method of the thread class is run (), which is called by the method Start () of the thread class to provide the code that our thread wants to execute. In order to specify our own code, we just need to overwrite it!
Method One: Inherit the thread class, overwrite the method run (), we rewrite the run () in the subclass of the thread class that was created, and the code to be executed by the thread is added. Here is an example:
public class MyThread extends Thread {
int count= 1, number;
public MyThread (int num) {
Number = num;
SYSTEM.OUT.PRINTLN ("Create thread" + number);
}
public void Run () {
while (true) {
SYSTEM.OUT.PRINTLN ("thread" + number + ": Count" + count);
if (++count== 6) return;
}
}
public static void Main (String args[]) {
for (int i = 0; i < 5; i++) New MyThread (i+1). Start ();
}
}
This method is straightforward and consistent with everyone's habits, but it also has a big drawback, that is, if our class has been inherited from a class (such as a small program must inherit from the Applet Class), then can not inherit the Thread class, then if we do not want to create a new class, what should we do?
We might as well explore a new approach: instead of creating subclasses of the thread class and using it directly, we can only pass our method as an argument to an instance of the thread class, somewhat like a callback function. But Java has no pointers, we can only pass an instance of a class that contains this method. So how do you limit the class to include this method? Use the interface, of course! (Although abstract classes can be met, but inheritance is required, and we are using this new approach, is not to avoid the limitations of inheritance?) )
Java provides interface java.lang.Runnable to support this approach.
Method Two: Implement Runnable interface
The Runnable interface has only one method run (), we declare our class implements the Runnable interface and provide this method, and write our thread code into it to complete this part of the task. But the Runnable interface does not have any support for threading, and we must also create an instance of the thread class, which is implemented by the thread class's constructor public thread (Runnable target). Here is an example:
public class MyThread implements Runnable {
int count= 1, number;
public MyThread (int num) {
Number = num;
SYSTEM.OUT.PRINTLN ("Create thread" + number);
}
public void Run () {
while (true) {
SYSTEM.OUT.PRINTLN ("thread" + number + ": Count" + count);
if (++count== 6) return;
}
}
public static void Main (String args[]) {
for (int i = 0; i < 5; i++) New Thread (New MyThread (i+1)). Start ();
}
}
Strictly speaking, it is possible to create an instance of the thread subclass, but it is important to note that the subclass must not overwrite the thread class's Run method, otherwise the thread will execute the Run method of the subclass, not the run method of the class that we use to implement the Runnable interface, so you might want to try Check it out.
Using the Runnable interface to enable multithreading allows us to accommodate all of the code in a class, and the downside is that we can only use a set of code, and if you want to create multiple threads and have different code for each thread, you still have to create the additional class, if that's the case, In most cases, it might not be as compact to inherit the Thread directly from multiple classes.
In summary, the two methods are different, we can use flexibly.
Let's take a look at some of the problems in multithreaded use.
Three: four state of thread
1. New status: Thread has been created but not yet executed (start () has not yet been called).
2. Executable state: Threads can execute, although not necessarily executing. The CPU time may be assigned to the thread at any time, allowing it to execute.
3. Death status: Normally the run () return causes the thread to die. Calling Stop () or destroy () also has the same effect, but is not recommended, the former will produce an exception, the latter is forced to terminate, will not release the lock.
4. Blocking status: Threads are not allocated CPU time and cannot be executed.
Four: Priority of threads
The priority of the thread represents the importance of the thread, and when multiple threads are in an executable state and waiting for CPU time, the thread dispatch system decides which CPU time to assign to the individual threads based on the priority of each thread, the higher priority thread has a greater chance of getting CPU time, and the low priority thread is not without opportunity. Just the chance to be smaller.
You can call methods GetPriority () and SetPriority () of the thread class to access the thread's priority, the thread's priority bounds are between 1 (min_priority) and ten (max_priority), and the default is 5 (norm_ Priority).
V: Synchronization of Threads
Because multiple threads of the same process share the same piece of storage space, it also poses a serious problem with access violations when it comes to convenience. The Java language provides a specialized mechanism to resolve this conflict, effectively avoiding the same data object being accessed by multiple threads concurrently.
Since we can guarantee that the data object is accessible only by means of the private keyword, we only need to propose a mechanism for the method, which is the Synchronized keyword, which consists of two usages: the Synchronized method and the synchronized block.
1. Synchronized method: Declare the Synchronized method by adding the Synchronized keyword to the method declaration. Such as:
Public synchronized void Accessval (int newval);
The Synchronized method Controls access to class member variables: Each class instance corresponds to a lock, and each synchronized method must obtain a lock on the class instance that invokes the method to execute, otherwise the owning thread is blocked, and once the method executes, the lock is exclusive until the lock is released from the method return , the blocked thread can then get the lock and re-enter the executable state. This mechanism ensures that at the same time for each class instance, at most one of its member functions declared as synchronized is in an executable state (since at most one can obtain the corresponding lock for that class instance), This effectively avoids access violations of class member variables (as long as all methods that may access the class member variable are declared as synchronized).
In Java, not only class instances, each class also corresponds to a lock, so we can also declare the static member function of the class as synchronized to control its access to static member variables of the class.
2. Use of thread pool (java.util.concurrent.ThreadPoolExecutor)The thread pool class is java.util.concurrent.ThreadPoolExecutor and is commonly constructed by:
Threadpoolexecutor (int corepoolsize, int maximumpoolsize,
Long KeepAliveTime, Timeunit unit,
Blockingqueue<runnable> WorkQueue,
Rejectedexecutionhandler handler)
Corepoolsize: Thread pool maintains a minimum number of threads
Maximumpoolsize: Thread pool maintains the maximum number of threads
KeepAliveTime: The thread pool maintains the idle time allowed by threads
Unit: The thread pool maintains the units of idle time allowed by threads
WorkQueue: Buffer queue used by the thread pool
Handler: thread pool processing policy for rejected tasks
A task is added to the thread pool by the Execute (Runnable) method, the task is an object of type Runnable, and the task is executed by the run () method of the Runnable type object.
When a task is added to the thread pool by the Execute (Runnable) method:
If the number in the thread pool is less than corepoolsize at this point, even if the threads in the thread pool are idle, create a new thread to handle the task being added.
If the number in the thread pool at this time equals corepoolsize, but the buffer queue Workqueue is not full, then the task is placed in the buffer queue.
If the number of threads in the thread pool is greater than corepoolsize, the buffer queue Workqueue full, and the number of thread pools is less than maximumpoolsize, a new thread is built to handle the task being added.
If the number of threads in the thread pool is greater than corepoolsize, the buffer queue is workqueue full, and the number in the thread pool equals maximumpoolsize, the task is handled by handler the policy specified. That is: the priority of the processing task is: Core thread corepoolsize, Task queue workqueue, maximum thread maximumpoolsize, if all three are full, use handler to handle the rejected task.
When the number of threads in the thread pool is greater than corepoolsize, if a thread is idle for more than KeepAliveTime, the thread is terminated. This allows the thread pool to dynamically adjust the number of threads in the pool.
The Unit optional parameter is a few static properties in Java.util.concurrent.TimeUnit:
nanoseconds,
microseconds,
MILLISECONDS,
SECONDS.
Workqueue commonly used are: Java.util.concurrent.ArrayBlockingQueue
Handler has four options:
Threadpoolexecutor.abortpolicy ()
Throw Java.util.concurrent.RejectedExecutionException exception
Threadpoolexecutor.callerrunspolicy ()
Retry adding the current task, he will automatically repeatedly call the Execute () method
Threadpoolexecutor.discardoldestpolicy ()
Abandon the old task
Threadpoolexecutor.discardpolicy ()
Abandon the current task
Second, relevant reference
A executorservice that uses a number of possible pool threads to perform each submitted task, typically using the Executors factory method configuration.
The thread pool resolves two different issues: because of the reduced overhead of each task invocation, they typically provide enhanced performance when performing a large number of asynchronous tasks, and can also provide methods for binding and managing resources, including the threads that are used to perform collection tasks. Each threadpoolexecutor also maintains some basic statistical data, such as the number of completed tasks.
For ease of use across a large number of contexts, this class provides a number of adjustable parameters and extension hooks. However, programmers are strongly advised to use the more convenient executors factory method Executors.newcachedthreadpool () (without a boundary pool, which can be used for automatic thread recycling), Executors.newfixedthreadpool ( int) (fixed-size thread pool) and Executors.newsinglethreadexecutor () (single background thread), which have predefined settings for most usage scenarios. Otherwise, when you manually configure and adjust this class, use the following guidelines:
core and maximum pool size
The threadpoolexecutor will automatically adjust the pool size based on the boundaries set by Corepoolsize (see Getcorepoolsize ()) and maximumpoolsize (see Getmaximumpoolsize ()). When a new task is committed in method execute (java.lang.Runnable), if the running thread is less than corepoolsize, a new thread is created to process the request, even if the other worker threads are idle. If you run more threads than corepoolsize and less than maximumpoolsize, a new thread is created only when the queue is full. If you set the same corepoolsize and Maximumpoolsize, a fixed-size thread pool is created. If you set Maximumpoolsize to a basic unbounded value (such as Integer.max_value), the pool is allowed to accommodate any number of concurrent tasks. In most cases, the core and maximum pool sizes are only set on a construction basis, but they can also be changed dynamically using setcorepoolsize (int) and setmaximumpoolsize (int).
on-Demand construction
By default, the core thread can be dynamically overridden with method Prestartcorethread () or prestartallcorethreads (), even if it was originally created and started only when a new task is needed.
Create a new thread
Create a new thread using Threadfactory. If not otherwise stated, threads are created in the same threadgroup using Executors.defaultthreadfactory (), and these threads have the same norm_priority priority and non-daemon status. By providing different threadfactory, you can change the name of the thread, the thread group, the priority, the daemon state, and so on. If threadfactory fails to create a thread when returning null from Newthread, the executor continues to run, but cannot perform any tasks.
Keep Active Time
If there are currently more than corepoolsize threads in the pool, these extra threads will terminate when the idle time exceeds KeepAliveTime (see Getkeepalivetime (Java.util.concurrent.TimeUnit)). This provides a way to reduce resource consumption when the pool is inactive. If the pool becomes more active later, you can create a new thread. You can also use Method Setkeepalivetime (long, java.util.concurrent.TimeUnit) to dynamically change this parameter. Use the value of Long.max_value timeunit.nanoseconds to effectively disable idle threads from the previous termination state before closing.
Queued
All blockingqueue can be used to transfer and maintain submitted tasks. You can use this queue to interact with the pool size:
A. If you run fewer threads than Corepoolsize, Executor always prefers to add new threads without queuing.
B. If the thread running is equal to or more than corepoolsize, Executor always prefers to join the request to the queue without adding a new thread.
C. If the request cannot be queued, a new thread is created unless the thread is created beyond maximumpoolsize, in which case the task is rejected.
There are three common strategies for queuing:
Submit directly. The default option for the work queue is synchronousqueue, which will submit tasks directly to the thread without maintaining them. Here, if there is no thread available to run the task immediately, attempting to join the task to the queue will fail, and a new thread will be constructed. This policy avoids locking when processing a collection of requests that may have internal dependencies. Direct submissions typically require unbounded maximumpoolsizes to avoid rejecting newly submitted tasks. This policy allows the possibility of an increase in the number of lines that are allowed to continue when the command arrives in a row that exceeds the average that the queue can handle.
unbounded queues. Using unbounded queues (for example, linkedblockingqueue that do not have a predefined capacity) causes new tasks to be queued when all corepoolsize threads are busy. This way, the created thread will not exceed corepoolsize. (therefore, the value of the maximumpoolsize is not valid.) When each task is completely independent of other tasks, that is, when task execution does not affect each other, it is appropriate to use a unbounded queue, for example, in a Web page server. This queueing can be used to handle transient burst requests, which allow the possibility of an increase in the number of lines that are allowed to occur when the command reaches an average of more than the queue can handle.
bounded queues. When using limited maximumpoolsizes, bounded queues (such as arrayblockingqueue) help prevent resource exhaustion, but may be difficult to adjust and control. The queue size and maximum pool size may need to be compromised: using large queues and small pools minimizes CPU usage, operating system resources, and context switching overhead, but can result in artificially reduced throughput. If tasks are frequently blocked (for example, if they are I/O boundaries), the system may schedule more threads than you permit. Using small queues typically requires a large pool size, high CPU utilization, but may encounter unacceptable scheduling overhead, which also reduces throughput.
Rejected Tasks
New tasks submitted in method execute (java.lang.Runnable) are rejected when Executor is closed and Executor uses a limited boundary for the maximum thread and work queue capacity and is already saturated. In both of these cases, the Execute method calls its Rejectedexecutionhandler rejectedexecutionhandler.rejectedexecution (java.lang.Runnable, Java.util.concurrent.ThreadPoolExecutor) method. The following four predefined handler policies are available:
A. In the default Threadpoolexecutor.abortpolicy, the handler is rejected and the runtime Rejectedexecutionexception is thrown.
B. In Threadpoolexecutor.callerrunspolicy, the thread invokes the execute itself that runs the task. This strategy provides a simple feedback control mechanism that can slow down the submission of new tasks.
C. In Threadpoolexecutor.discardpolicy, the tasks that cannot be performed are deleted.
D. In Threadpoolexecutor.discardoldestpolicy, if the execution program has not been closed, the task at the head of the work queue is deleted, and then the execution of the program is retried (repeat this process if it fails again).
It is also possible to define and use other kinds of rejectedexecutionhandler classes, but doing so requires great care, especially when the policy is used only for specific capacity or queueing policies.
Hook method
This class provides protected overridable BeforeExecute (Java.lang.Thread, java.lang.Runnable) and AfterExecute (Java.lang.Runnable, Java.lang.Throwable) method, which is called before and after each task is executed. They can be used to manipulate the execution environment, for example, reinitialize ThreadLocal, collect statistics, or add log entries. In addition, you can override method terminated () to perform all special processing that needs to be done after the Executor is completely terminated.
If the hook or callback method throws an exception, the internal worker thread fails sequentially and terminates abruptly.
Queue Maintenance
Method Getqueue () allows access to the work queue for monitoring and debugging purposes. Strongly oppose the use of this method for any other purpose. Both the Remove (java.lang.Runnable) and Purge () methods can be used to help with storage reclamation when a large number of queued tasks are canceled.
First, examples
To create the Testthreadpool class:
Import Java.util.concurrent.arrayblockingqueue;import Java.util.concurrent.threadpoolexecutor;import Java.util.concurrent.timeunit;public class Testthreadpool {private static int producetasksleeptime = 2; private static int producetaskmaxnumber = 10; public static void Main (string[] args) { //constructs a thread pool threadpoolexecutor threadPool = new Threadpoolexecutor (2, 4, 3 , Timeunit.seconds, New arrayblockingqueue<runnable> (3), new Threadpoolexecutor.discardoldestpolicy ()); for (int i = 1; I <= producetaskmaxnumber; i++) { try { String task = "[Email protected]" + i; SYSTEM.OUT.PRINTLN ("Create task and commit to thread pool:" + Task); Threadpool.execute (New Threadpooltask (Task)); Thread.Sleep (Producetasksleeptime); } catch (Exception e) { e.printstacktrace ();}}}}
To create the Threadpooltask class:
Import Java.io.serializable;public class Threadpooltask implements Runnable, Serializable {private Object attachdata; Threadpooltask (Object tasks) { this.attachdata = tasks;} public void Run () { System.out.println ("Start execution Task:" + Atta Chdata); Attachdata = null; } public Object Gettask () { return this.attachdata;}}
Execution Result:
Create the task and submit it to the thread pool: [Email protected] 1
Start performing tasks: [email protected] 1
Create the task and submit it to the thread pool: [Email protected] 2
Start performing tasks: [Email protected] 2
Create the task and submit it to the thread pool: [Email protected] 3
Create the task and submit it to the thread pool: [Email protected] 4
Start performing tasks: [Email protected] 3
Create the task and submit it to the thread pool: [Email protected] 5
Start performing tasks: [Email protected] 4
Create the task and submit it to the thread pool: [Email protected] 6
Create the task and submit it to the thread pool: [Email protected] 7
Create the task and submit it to the thread pool: [Email protected] 8
Start performing tasks: [Email protected] 5
Start performing tasks: [Email protected] 6
Create the task and submit it to the thread pool: [Email protected] 9
Start performing tasks: [email protected] 7
Create the task and submit it to the thread pool: [Email protected] 10
Start performing tasks: [Email protected] 8
Start performing tasks: [Email protected] 9
Start performing tasks: [email protected] 10
Copyright notice: I feel like I'm doing a good job. I hope you can move your mouse and keyboard for me to order a praise or give me a comment, under the Grateful!_____________________________________________________ __ Welcome reprint, in the hope that you reprint at the same time, add the original address, thank you with
Java Thread Summary