What is a thread
Each process has its own set of variables, while threads share data.
Without a multithreaded program, calling Thread.Sleep does not create a new thread that pauses the activity of the current thread. The program cannot interact with the program until it is finished.
Use threads to provide opportunities for other tasks
Placing the code in a separate thread, the event dispatch thread will focus on the event and handle the user's actions.
A simple procedure for performing a task in a separate thread:
Move the task code into the run method of the class that implements the Runnable interface.
public interface Runnable{ void run();}Runnable r = () -> { task code; };
Create a Thread object from Runnable:
Thread t = new Thread(r);
To start a thread:
t.start();//启动这个线程,将引发调用 run() 方法。新程序将并发运行。
Break Thread in
The thread's Run method executes the method weight after the last statement, and is returned by executing a return statement, or if no exception is caught in the method, the program terminates.
Early Java has a stop method that can terminate a thread and is currently deprecated.
There is no way to force a thread to terminate. However, theinterrupt method can be used to request a terminating thread.
When a thread calls the interrupt method, the interrupt state of the thread is placed. This is every thread that has a Boolean flag. Each thread checks this flag from time to times to determine if the thread has been interrupted.
Determines whether the thread is set, the CurrentThread method obtains the current thread, and the Isinterrupted method determines whether this thread is set:
Thread.currentThread().isInterrupted()
When you call the interrupt method on a blocked thread (call sleep or wait), the blocking call is interrupted by the interrupted Exception exception.
Interrupting a thread does not cause the program to terminate, but it takes its attention. The interrupted thread can decide how to respond to interrupts. The generic thread will simply break the interrupt as a terminating request.
If the sleep method is called when the interrupt state is set, it does not hibernate. It will clear the state thrown InterruptedException
.
There are two reasonable options for exceptions:
- Called in the catch clause
Thread.currentThread().interrupt()
to set the break state. It can be detected by the caller.
- By
throws InterruptedException
marking your method, the caller can catch the exception.
//java.lang.Threadvoid interrupt() //发送中断线程请求。中断状态为 true。如果线程 sleep 抛出异常。static boolean interrupted() //测试线程是否中断。静态方法副作用,中断状态重置为 falseboolean isInterrupted() //测试线程是否被终止。static Thread currentThread() //当前执行线程的 Thread 对象
Thread state
There are 6 kinds of states:
- New (newly created)
- Runnable (can be run)
- Blocked (blocked)
- Waiting (Wait)
- Timed Waiting (timed Wait)
- Terminated (terminated)
Use the GetState method to determine the state of the thread.
Newly created thread new
When a new thread is created by using the new operator, for example new Thread(r)
, the thread has not started running.
can run thread Runnable
Once the Start method is called, the thread is in the runnable state.
A running selection may or may not be running.
The preemptive dispatch system gives each running thread a time slice to perform the task. When the time slice runs out, the operating system deprives the thread of its running power and gives another thread the chance to run.
Blocked threads and waiting threads Blocked waiting
This state does not allow any code and consumes the least resources. Know that the thread scheduler reactivated it. The details depend on how it has been inactive.
- When a thread view acquires an internal object lock, and the lock is held by another thread, it goes into a blocking state . When the other thread releases the lock, and the thread scheduler runs this thread to hold it, the thread becomes non-blocking.
- When a thread waits for another thread to notify the scheduler of a condition, he enters the waiting state himself.
Object.wait
Thread.join
This occurs when a call or method, or java.util.concurrent
a wait or time is in Lock
Condition
progress. The blocked state differs greatly from the wait state.
- Calling some methods will cause the thread to enter a timed wait state . This status is maintained until the time-out expires or the appropriate notification is received. The method with the timeout parameter has a and,,, and
Thread.sleep
Object.wait
Thread.join
Lock.tryLock
Condition.await
a timed version.
Terminated thread Terminated
Two reasons are terminated:
- Natural death due to the normal exit of the Run method
- No catch exception terminated the Run method accidental death
Thread Attribute Thread priority
In a Java program, each thread has a priority. By default, a thread inherits the priority of its parent thread.
You can use the SetPriority method to increase or decrease the priority of any one thread. (1~10)
Using the static void yield method causes the current execution thread to be in a concession state, with other running threads having at least the same high priority as this thread, then these threads are then dispatched.
Daemon Threads
t.setDaemon(true);
the thread is loaded as a daemon thread by calling.
The only purpose is to provide services to other threads. The virtual machine exits when only the daemon thread is left. such as a timed thread, timed to send a signal to other threads.
The daemon thread should never access an intrinsic resource, such as a file or a database. Because it will be interrupted at any time.
Exception handler not caught
The thread's Run method cannot throw any of the checked exceptions, and the non-checked exception causes the thread to terminate. At this point the thread dies, and the exception is passed to a processor for the uncaught exception before death.
The processor must be in a Thread.UncaughtExceptionHandler
class that implements the interface. Class has a methodvoid uncaughtException(Thread t, Throwable e)
You can use setUncaughtExceptionHandler
a method to install a processor for any thread.
Thread.setDefaultUncaughtExceptionHandler
installs a default processor for all threads in a static way.
The processor is not installed for a standalone thread, and the processor is the object of that thread ThreadGroup
.
Thread Group
A thread group is a centrally managed collection of threads. By default, all threads that are created belong to the same thread group.
The Threadgroup class implements the Thread.UncaughtExceptionHandler
interface. Here's how it works uncaughtException
:
- If the line threads the parent thread group, then the method of the parent thread group
uncaughtException
is called.
- Otherwise, if the
Thread.getDefaultExceptionHandler
method returns a non-empty processor, the processor is called.
- Otherwise, if
Throwable
it is ThreadDeath
an instance, nothing is done.
- Otherwise, the name of the thread and
Throwable
the stack trace are output to the System.err
top.
Synchronous
Two or more two threads need to share access to the same data. If you do not use synchronization, the thread invokes a method that modifies the state of the object, which produces corruption objects. This situation is a competitive condition .
Explanation of competitive conditions
When two thread views update the same account at the same time, some problems arise, assuming they execute the instructions at the same time:
accounts[to] += amout;
Processing process:
- will be
accouts[to]
loaded into the register.
- Increased
amount
.
- Write the results back
accounts[to]
.
If the 1th thread finishes executing steps 1 and 2, it is deprived of the right to run. The 2nd thread was awakened and the same item in the accounts array was modified. Then, the 1th thread is awakened and the 3rd step is completed.
This action allows thread 1 to erase the operations that are done by thread 2. The total amount is not correct.
Thread 1 |
Thread 2 |
Register Accouts[to] |
Accouts[to] |
Load Accouts[to] |
|
Threads 1 10 |
10 |
Increase Amout |
|
Threads 1 12 |
10 |
|
Load Accouts[to] |
Threads 2 10 |
10 |
|
Increase Amout |
Threads 2 12 |
10 |
|
Write Accouts[to] |
Thread 2 Write 12 |
12 |
Write Accouts[to] |
|
Thread 1 Write 12 |
12 |
The state of the bank account object will never appear corruption if it is able to ensure that the method runs before the thread loses control.
Lock Object Reentrantlock re-entry lock
There are two mechanisms to prevent code blocks from being disturbed by concurrent access:
- Synchronized keywords
- Java SE 5.0 introduces the Reentrantlock class
The Synchronized keyword automatically provides a lock and related "conditions" for most small display locks.
The Java.util.concurrent framework provides independent classes for these underlying mechanisms.
The basic structure for protecting code with Reentrantlock is as follows:
private Lock bankLock = new ReentrantLock();bankLock.lock();try{ critical section} finally { bankLock.unlock();}
This structure ensures that only one thread can enter the critical section at any time. Once a program uses the lock method to block an object, no other program can pass the lock statement. When other threads call lock, they are blocked until the first thread releases the lock object.
Locks are reentrant , and threads can repeatedly acquire locks that are already held. The lock maintains a hold count to track nested calls to the lock method, with each entry counter incremented by 1. The thread calls unlock every time it calls lock to release the lock. Because of this feature, code that is protected by one lock can invoke another method that uses the same lock.
Reentrantlock re-enter the lock, you can also build a lock with a fair policy.
Conditional Object Condition
Use conditional objects to manage threads that have acquired a lock but are not able to do useful work. Conditional objects are often referred to as conditional variables.
A lock object can have one or more related conditional objects. Obtain a conditional object using the Newcondition method.
class Bank{ private Condition sufficientFunds; public Bank(){ ... sufficientFunds = bankLock.newCondition(); }}//发现 transfer 方法余额不足,调用sufficientFunds.await();
The thread that calls the await method and the thread waiting to get the lock are inherently different.
The thread that uses the await method enters the waiting set for the condition, and when the lock is available, it is not unblocked immediately until the other thread calls the Signalall method on the same condition.
When another thread finishes the operation, it should call:
sufficientFunds.singnalAll();
At this point, reactivate all threads that are waiting because of this condition. Continue execution from the blocked place.
One thread calls the await method, and the other program does not call the Signalall method, then it is a deadlock and is blocked forever.
The signal method can randomly dismiss a thread's blocking state. But if there is another block, and no other thread calls singnal again, the thread will deadlock.
Synchronized keywords
Key to locks and conditions:
- Locks are used to protect code fragments, and only one thread can execute the protected code at any time.
- A lock can manage a view into a thread that is protected by a code snippet.
- A lock can have one or more related conditional objects.
- Each conditional object manages programs that have entered the protected code snippet but cannot run.
Every object in Java has an internal lock, and if a method is declared with the Synchronized keyword, the lock on the object will protect the entire method. When the method is called, the thread must obtain an internal object lock.
public synchronized void method(){ method body}//等价public void method(){ this.intrinsicLock.lock(); try { method body } finally { this.intrinsicLock.unlock(); }}
Synchronized internal object locks have only one related condition.
- The wait method adds a thread to the wait set.
- The Notifyall/notify method unlocks the blocking state of the waiting thread.
- They are the final method of the Object class.
is equivalent to the following method:
intrinsicLock.await();intrinsicLock.signallAll();intrinsicLock.signall();
There are some limitations to internal locks:
- You cannot interrupt a thread that is attempting to acquire a lock.
- The timeout cannot be set when attempting to acquire a lock.
- Each lock has only a single condition and may not be enough.
Recommendations for which lock to use:
- It is best not to use lock/condition or synchronized keywords. In many cases you can use a mechanism in the java.util.concurrent package, which will handle all the locking.
- If synchronized is suitable for a program, use it as much as possible, and it can reduce the amount of code written.
- The lock/condition is used only when the unique features provided by the lock/condition structure are needed in particular.
Synchronous blocking synchronized (obj) {...}
A thread can obtain a lock through a synchronous method. Locks can also be obtained by entering a synchronous block:
synchronized(obj){ critical section}//获得 obj 的锁
The lock object is created to use only the locks held by each Java object.
Sometimes programmers use the lock of an object to achieve extra atomicity, which is actually called client stabilization .
Monitor concept
Locks and conditions are powerful tools for thread synchronization, but they are not object-oriented.
Monitors can be implemented without locking, to ensure the security of multithreading.
Monitor Features:
- The monitor contains only the classes of the private domain.
- Each monitor class has an associated lock on the object.
- Use this lock to lock all methods.
- The lock can have any number of related conditions.
If a method is declared with the Synchronized keyword, it behaves as if it were a monitor method.
Three methods Java objects are different from monitors, and security drops:
- The domain does not require that it must be private.
- The method does not require that the synchronized must be.
- The internal lock is available to the customer.
Volatile Domain
If you write a value to a variable, and the variable may be read by another thread, or read from a variable that might have been written by another thread, you must use synchronization.
The volatile keyword provides a lock-free mechanism for synchronizing access to an instance domain.
If a domain is volatile, then the compiler and the virtual machine know that the domain is likely to be updated concurrently by another thread.
private volatile boolean done;public boolean isDone(){ return done; }public void setDone(){ done = true; }
Volatile does not provide atomicity. Cannot ensure that read, flip, and write are not interrupted.
done = !done
Final variable
A shared domain can be accessed securely using the final shared domain.
final Map<String, Double> accounts = new HashMap<>();
The thread will only be able to see this accounts variable when the constructor finishes constructing.
Without final, there is no guarantee that other threads will see the updated value, and can just look at null instead of the newly constructed HashMap.
Atomic Nature
java.util.concurrent.atomic
There are many classes in the package that use efficient machine-level directives to ensure the atomicity of other operations.
Dead lock
It is possible that all threads are blocked because each thread waits for more money to be deposited. Such a state becomes a deadlock.
Thread Local Variables
Avoid sharing variables, and use the ThreadLocal helper class to provide each thread with its own instance.
Lock Test and timeout
Cautious application of Locks:
if(myLock.tryLock()){ try { ... } finally { myLock.unlock(); }} else { do something else}
When you can call Trylock, use the supermarket parameters:
if (myLock.tryLock(100, TimeUnit.MILLISECONDS)) ...
Timeunit is an enumeration type, and the timeout parameter lets the thread that is interrupted during the wait throw an exception. Allows the program to break the deadlock.
Read/write Lock
The Java.util.concurrent.locks package defines two lock classes.
Required steps for read/write Lock:
Constructs a Reentrantreadwritelock object
private ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
Extracting Read and write locks
private Lock readLock = rwl.readLock();
private Lock readLock = rwl.writeLock();
Read locks on all acquisition methods
public double getTotalBalance(){ readLock.lock(); try {...} finally { readLock.unlock(); }}
Write locks on all modification methods
public void transfer(...){ writeLock.lock(); try {...} finally { writeLock.unlock();}}
Why discard the stop and suspend methods
The Stop method is inherently unsafe.
Suspend methods often lead to deadlocks.
blocking queues
Blocking queues cause threads to block when the view adds elements to the queue and the queue is full, or if you want to move the elements out of the queue and the queue is empty.
Thread-Safe collection of efficient mappings, sets, and queues
The Java.util.concurrent package provides efficient implementations of mappings, ordered sets, and queues:
- Concurrenthashmap
- Concurrentskiplistmap
- Concurrentskiplistset
- Concurrentlinkedqueue
These collections use sophisticated algorithms that minimize competition by allowing concurrent access to different parts of the data structure.
The collection returns a weakly consistent iterator. Iterators do not necessarily reflect all the modifications that they are constructed, but they do not return the same value two times, and do not throw a concurrentmodificationexception exception.
The CONCURRENTHASHMAP default supports up to 16 write threads concurrently. If more than 16 is written at the same time, other threads will be temporarily blocked. You can specify a larger number of constructors.
Atomic update of MAP entries
Concurrenthashmap There are only a few ways to achieve atomic updates.
The following are not thread-safe:
Long oldValue = map.get(word);Long newValue = oldValue == null ? 1 : oldValue + 1;map.put(word, newValue);//Error 可能不会替换 oldValue
The traditional method uses the replace operation, which replaces the original value atomically with a new value, provided that no other thread has previously replaced the original value with a different value.
do { oldValue = map.get(word); newValue = oldValue == null ? 1 : oldValue + 1;}while(!map.replace(word, oldValue, newValue));
or using ConcurrentHashMap<String, AtomicLong>
or using in Java SE 8 ConcurrentHashMap<String, LongAdder>
:
map.putIfAbsent(word, new LongAdder());map.get(word).increment();
The map function accepts the key and the associated value, and it calculates the new value.
map.compute(word, (k, v) -> v == null ? 1 : v + 1);
Null values are not allowed in Concurrenthashmap.
Batch operation for and diverging column mappings Concurrenthashmap
- The search provides a function for each key or value until the function produces a non-null result. Then the search terminates, returning the result of this function.
- The sum of all keys or values, using an additive function provided by the lock.
- ForEach provides a function for all keys or values.
There are 4 versions of each operation:
- Operationkeys: Handling Keys
- Operationvalues: Handling values
- Operation: Handling Keys or values
- Operationentries: Handling Map.entry objects
Concurrent Set View
There is no Concurrenthashset class, but you can use Concurrenthashmap to create a view.
Set<String> words = ConcurrentHashMap.<String>newKeySet();//keySet 方法包含一个默认值,在为集增加元素时使用Set<String> words = map.keySet(1L);words.add("Java");
Copy of the Write array
Copyonwritearraylist and Copyonwritearrayset are thread-safe collections where all the modified threads replicate the underlying array.
Parallel array algorithm
The static Arrays.parallelsort method can sort a primitive type value or an array of objects.
The Parallelprefix method, which replaces each array element with the cumulative result of a prefix corresponding to a given union operation.
Older Thread-Safe collections
Vector and Hashtable classes provide a thread-safe implementation of dynamic arrays and hash lists.
Any collection class can become thread-safe by using the synchronization wrapper (collections. synchronized*).
If you want to iterate over the collection when another thread is likely to make modifications, you still need to use a "client" Lock:
synchronized (synchHashMap) { Iterator iter = synchHashMap.keySet().iterator();
It is best to use the java.util.conncurrent
collection defined in the package without using the synchronization wrapper. In particular, if they are accessing a different bucket, because ConcurrentHashMap
it has been carefully implemented, multithreading can access it and not block each other.
An exception is a list of arrays that are often modified. In that case, the synchronization ArrayList
can be better thanCopyOnWriteArrayList
Callable and future
Runnable encapsulates an asynchronous run task, which can be imagined as an asynchronous method without parameters and return values.
Callable is similar to Runnable, but has a return value. The callable interface is a parameterized type with only one method call.
The future saves the results of an asynchronous calculation. You can start a calculation, give the future object to a thread, and then forget about it. The owner of the future object can obtain it after the result has been calculated.
The call to the Get method is blocked until the calculation is complete. If the second method's call times out before the calculation is complete, a TimeoutException exception is thrown out. If the thread running the calculation is interrupted, all two methods will be thrown out of the intermptedexception. If the calculation is complete, the Get method returns immediately.
If the calculation is still in progress, the IsDone method returns False if it is complete and returns true.
You can cancel the calculation by using the Cancel method. If the calculation has not started, it is canceled and no longer starts. If the calculation is running, it is interrupted if the Maylnterrupt parameter is true.
Actuator
If you create a lot of short-life threads in your program, you should use a thread pool.
A thread pool contains many idle threads that are ready to run. When you give the Runnable object to the thread pool, a thread calls the Run method. When the Run method exits, the thread does not die, but is prepared to service the next request in the pool.
Another reason to use the thread pool is to reduce the number of concurrent threads. Creating a large number of threads can greatly degrade performance and even crash the virtual machine. If you have an algorithm that creates many threads, you should use a "fixed" thread pool of threads to limit the total number of concurrent threads.
The Actuator (Executor) class has many static factory methods used to build the thread pool.
- Newcachedthreadpool Create new thread if necessary; idle thread is reserved for 60 seconds
- Newfixedthreadpool The pool contains a fixed number of threads, and idle threads are kept
- Newsinglethreadexecutor a "pool" of only one thread, which sequentially executes each committed task (similar to the Swing event allocation thread)
- Newscheduledthreadpool fixed thread pool built for scheduled execution, instead of Java.util.Timer
- Newsinglethreadscheduledexecutor single-threaded "pool" Built for scheduled execution
Thread pool
Newcachedthreadpool
Newfixedthreadpool
Newsinglethreadexecutor
These 3 methods return objects of the Threadpoolexecutor class that implement the Executorservice interface.
You can submit a Runnable object or callable object to Executorservice using one of the following methods:
Future submit(Runnable task)Future submit(Runnable task, T result)Future submit(Callable task)
The pool performs the submitted tasks as early as possible at a convenient time.
When you invoke submit, you get a future object that you can use to query the status of the task.
- The first Submit method returns an oddly-like future. You can use such an object to invoke IsDone, Cancel, or iscancelled. However, the Get method simply returns NULL when it is finished.
- The second version of Submit also submits a Runnable, and the Get method of the future returns the specified result object when it is completed.
- The third version of submit submits a callable, and the returned future object will get it when the calculation results are ready.
Call the Shutdown method to start the closed sequence of the pool. The closed actuator no longer accepts new tasks. When all tasks are completed, threads in the thread pool die.
Call the Shutdownnow method, which cancels all tasks that have not yet started and attempts to break the running thread.
Here's a summary of what you should do when using connection pooling:
- Call the static method Newcachedthreadpool or Newfixedthreadpool in the Executors class.
- Call submit to submit the Runnable or callable object.
- If you want to cancel a task, or if you commit a callable object, save the returned future object.
- When no more tasks are committed, call shutdown.
Scheduled execution
The Scheduledexecutorservice interface has a method that is designed for scheduled execution or repetitive execution of tasks. The latter two methods implement this interface.
Control task groups
The InvokeAll method submits all objects to a collection of callable objects and returns a list of future objects that represent the solution for all tasks.
Fork-join Frame
Some applications use a large number of threads, but most of them are idle. For example, a WEB server might use one thread for each connection. Other applications may use a single thread for each processor core to perform computationally intensive tasks, like or video processing. The Fork-join framework was introduced in Java SE 7 to support the latter class of applications. Suppose there is a processing task that can be naturally decomposed into subtasks.
if (problemSize < threshold) solve problem directlyelse { break problem into subproblems recursively solve each subproblem combine the results}
Can complete futrue
The traditional way to handle non-blocking calls is to use the event handler, which registers a processor for actions to occur after the task is completed.
Synchronous device
The Java.util.concurrent package contains classes that manage the set of mutually cooperative threads.
Signal Volume
A semaphore manages many licenses (permit).
Countdown Door Bolt
A countdown Gate Bolt (countdownlatch) lets a thread set wait until the count changes to 0. The countdown door bolt is disposable. Once the count is 0, it can no longer be reused.
Barrier barriers
The Cyclicbarrier class implements a staging point (rendezvous) called a barrier (barrier). Consider a scenario in which a large number of threads run in different parts of a calculation. When all parts are ready, you need to combine the results. When a thread finishes its part of the task, we let it run to the barrier. Once all the threads have reached the barrier, the barrier is revoked and the thread can continue to run.
Switching device
When two threads work on two instances of the same data buffer, the switch can be used (Exchanger) Typically, one thread fills the buffer with data, and the other consumes the data. When they are all finished, swap buffers with each other.
Synchronization queue
A synchronization queue is a mechanism for pairing producers with consumer threads. When a thread calls the Put method of synchronousqueue, it blocks until another thread calls the Take method, and vice versa. Unlike Exchanger's case, data travels only in one direction, from producers to consumers. Even though the Synchronousqueue class implements the Blockingqueue interface, conceptually it is still not a queue. It does not contain any elements, and its size method always returns 0.
Java Core Technology Volume 18. Java concurrency