Concurrent
concurrency exists on both single-core and multicore CPUs, and for single-core CPUs, concurrency is achieved by rotation time slices.
Thread Thread Object
With Thread
objects, there are two ways to create concurrent programs:
- Create and manage threads directly. When the program starts an asynchronous task, it creates a thread directly.
- Abstract the thread management and hand over the tasks of the Concurrency section
executor
.
Creation of Threads
There are two ways of creating threads:
- Provides an
Runnable
object that implements an interface.
- Sub-class
Thread
.
The pros and cons of both approaches?
Runnable
A little better overall.
Runnable
the interface is more flexible because it can continue to subclass a class
Runnable
Interface can be adapted to concurrent
the advanced threading Management API in a package
The basic state of the thread
The thread has the following status:
-
NEW
: Thread has been created but not yet called start ()
start execution.
-
RUNNABLE
: Thread has started running in the JVM, but there may be waiting for system resources to run.
-
BLOCKED
: Thread is waiting for a monitor lock to enter a synchronized
block. It is also possible that this thread has just finished executing , wait ()
, and the other threads are getting wait ()
object monitor lock .
-
waiting
: Thread enters the wait state, the following methods will cause the thread to enter wait ()
Status:
-
Object.wait ()
-
join ()
-
locksupport.park
-
Code>timed_waiting : Thread enters a time-limited wait, and the method causes the thread to enter this state:
-
thread.sleep
-
Obj Ect.wait (Long)
-
thread.join (long)
-
locksupport.parknanos
locksupport.parkuntil
-
TERMINATED
: Thread execution ends.
Attention:
When thread a invokes the Synchronized
method of an object, the thread acquires the object's intrinsic lock, and the thread's state is RUNNABLE. Other threads If you want to get this lock, you'll get into blocked status.
When thread A calls the wait
method, thread a releases the lock on the object (but throws back the lock that holds the other object, if any), and then the thread goes to the waiting state. (If many of the previous objects pending on this lock, will the other thread be awakened after entering wait?)
When another thread B is invoked on the same object (that is wait
, the same lock that thread a releases) notify
notifyAll
, the thread a state is converted from waiting to BLOCKED. At this point, thread A does not automatically get To a lock or a state into RUNNABLE, in fact, thread A also competes with other blocked threads for this lock.
Both the waiting and BLOCKED states prevent threads from running, but the difference is large.
The waiting state must be called by another thread notify
to explicitly convert to the BLOCKED state. The waiting state never translates directly into RUNNABLE.
When a RUNNABLE thread releases a lock (normal end or waiting
), a blocked thread is automatically awakened.
notify
And the notifyAll
difference?
notify
Wake up all threads that have the same lock on the first thread of the same lock wait
notifyAll
wait
, but the highest priority executes first
Thread.sleep
Thread.sleep
Causes the current thread to suspend temporarily for a period of time, and other threads can have the opportunity to get to the CPU time.
Two APIs:
Thread.sleep(long ms)Thread.sleep(long ms, long ns)
Time is not accurate due to the limitations of the underlying OS implementation.
Sleep can be interrupted when thread A is dormant and another thread B calls A.interrupt (), thread a throwsInterruptedException
Interrupt Interrupt
Interrupt stops the current thread's ongoing tasks and takes other things. It is up to the programmer to decide how a thread should respond to an interrupt.
Response interruption
Depending on the length of the current task, do a different treatment:
When a thread is calling a method that will be thrown frequently, InterruptedException
it can be try...catch
handled by capturing and doing it in catch
. There are many ways to throw InterruptedException
, for example Thread.sleep
, sleep
the interrupt behavior is designed to terminate the current operation and throw an exception.
for (int i = 0; i < ary.length; i++) { try { Thread.sleep(4000); } caatch (InterruptedException e) { return; } System.out.println(importantInfo[i]);}
When a thread executes a long task and the task is not thrown InterruptedException
. Then we need to constantly detect that the current line threads is not interrupted:
for (int i = 0; i < inputs.length; i++) { heavyCrunch(inputs[i]); if (Thread.interrupted()) { // or return; throw new InterruptedException(); }}
Flag bits for interrupts
The interrupt mechanism is controlled by a flag of the internal identity interrupt state:
- When called
Thread.interrupt
, this flag is set.
- When called
Thread.interrupted
, the flag is cleaned.
- When
Thread.isInterrupted
the query break state is called, the flag is not changed.
- If any method
InterruptedException
exits, the interrupt flag is cleared (but may be set immediately).
Join
join
method allows a thread to wait for another thread to execute before executing. sleep
as well, join
the way to respond to interrupts is to exit and throw InterruptedException
.
Thread synchronization
Inter-thread communication relies primarily on access to open fields or objects referenced by fields. Will bring two questions:
- Threading interference (thread interference)
- Memory consistency Error (consistency)
The mechanism for preventing these two kinds of errors is thread synchronization . However, thread synchronization can lead to inter-thread contention (thread contention). Both hunger and live lock are the performance of thread competition .
Threading interference-thread interference
Refers to a statement that may be split into many steps by a virtual machine, however, when two threads cross execution, thread A's execution results in an inaccurate run of thread B. For example, thread A executes, c++
thread B executes c--
, start two threads read to c the value is 0, if thread B finishes after A, then the result is -1
instead 0
.
Memory consistency Error-consistency error
Memory Consistency Error refers to a thread that has inconsistent values for the same piece of data. The key to preventing such errors is to guarantee happens-before relationships . Like what:
int count = 0;
Thread A executes:
count++;
Thread B Prints count
the value:
System.out.println(count);
So the result of thread B printing may be 0
that because thread A's self-increment operation does not have a happens-before relationship with the B print statement.
The happens-before Relationship guarantees that the memory write action caused by a statement is visible to the other statement.
How to establish happens-before relationship ?
- The same thread, the preceding instruction is always executed before the following instruction
- Releasing monitor lock(leaving
synchronized
a code block or method) always occurs before acquiring the same monitor lock(entering a synchronized
code block or method). Due to the happens-before relationship propagation, the method of releasing a lock, or a block of code, is always performed before a lock or block of code is acquired.
- Write
volatetile
variables are always executed before reading.
- Call to
Thread.start
establish two kinds of happens-before relationships :
Thread.start
The preceding statement is Thread.start
executed before the
Thread.start
The preceding statement executes before the new thread statement
- Thread a ends and causes thread B
Thread.join
to return, and all the statements in thread A are Thread.join
executed before the statement that follows Line B
Thread Synchronization methods
The Java language level provides two methods:
- Synchronized method
- synchronzied statements
Attention:
- Constructors cannot be
synchronized
decorated, or a compilation error occurs.
- The construction of an object must be done in the same thread.
Do not expose a reference to a field earlier. For example, add the following statement to the constructor:
instances.add(this) //就会导致构造函数并未完成, 却将它通过 instances 暴露出去了.
Intrinsic Lock/monitor Lock
The mechanism of synchronization is built on intrinsic lock , also known as Monitor lock . intrinsic Lock action is
- Forces the state of the exclusive object (as long as a thread has a intrinsic lock, the other thread is not getting the lock)
- Establish a happens-before relationship
- The visibility of the state change is guaranteed.
The lock in Synchronized method
When a thread calls a synchronized method , the thread automatically obtains the intrinsic lockof the object. and release it in the following cases:
- method returns normally
- An uncaught exception has occurred
When a thread calls a static synchronized method , the thread acquires the lock of the object associated with the object Class
. So the static synchronization method locks and instance locks are different.
synchronzied statements
Writing:
public void addName(String name) { synchronized(this) { lastName = name; nameCount++; } nameList.add(name); }
Note: In synchronized method
or, synchronzied statements
you want to avoid synchronizing code (methods or blocks of code) for other objects.
Synchronous code re-entry
- One thread cannot get locks owned by other threads
- A thread can acquire a lock that it already owns
Atomic Access
It means: an operation that cannot be interrupted
Atomic operations in Java:
- Read or change references to reference types
- Read or change the base type (
long
and double
except )
- Read or change
volatile
variables of all types (including references, long
, double
)
Atomic operations are not split, so there is no need to worry about thread interference, but still pay attention to memory consistency (consistency) issues.
volatile
memory consistency errors can be avoided because the write volatile
variable establishes a happen-before relationship: The write is better than the subsequent read .
synchronized method
and synchronized statements
will guarantee atomic operation.
Livenessdeadlock
Deadlocks describe a situation in which two or more threads enter a permanent block and wait for each other.
Avoid methods: The lock is in the same order.
How to troubleshoot? With jstack you can view:
jstack <pid>
Java stack information for the threads listed above:==================================================="Thread-1": at basic.DeadlockBower$Friend.bowBack(DeadlockBower.java:32) - waiting to lock <0x0000000795706590> (a basic.DeadlockBower$Friend) at basic.DeadlockBower$Friend.bow(DeadlockBower.java:28) - locked <0x00000007957065d8> (a basic.DeadlockBower$Friend) at basic.DeadlockBower$2.run(DeadlockBower.java:49) at java.lang.Thread.run(Thread.java:745)"Thread-0": at basic.DeadlockBower$Friend.bowBack(DeadlockBower.java:32) - waiting to lock <0x00000007957065d8> (a basic.DeadlockBower$Friend) at basic.DeadlockBower$Friend.bow(DeadlockBower.java:28) - locked <0x0000000795706590> (a basic.DeadlockBower$Friend) at basic.DeadlockBower$1.run(DeadlockBower.java:43)
Starvation
Starvation describes a situation in which threads cannot access shared resources for long periods of time and cannot make progress
Livelock
Description: Two threads respond to each other's behavior, resulting in no substantial progress
Guarded Blocks
Threads often coordinate their behavior, the most common method of coordination is guarded block:
public void guardedJoy() { // Simple loop guard. Wastes processor time. Don‘t do this! while (!joy) { } System.out.println("Joy has been achieved"); }
The above code joy
determines whether or not to proceed in a state of constant detection. This is a very CPU-intensive time.
Better should be used Object.wait()
to hang up the current thread.
public synchronized void guardedJoy() { // This guard only loops once for each special event, which may not be // the event we‘re waiting for. while (!joy) { try { wait(); } catch (InterruptedException e) {} } System.out.println("Joy and efficiency have been achieved!");}
It is important to be sure that wait()
in a loop, because you cannot guarantee:
- Yes
InterruptedExcpetion
or normal wake up cause the wait()
end
- Whether the awakened thread will
joy
change the value (especially in notifyAll
)
Consumer and producer Models
Solved, decoupling the producers and consumers, and more reasonable use of CPU time.
Immutable objects
Immutable objects are objects whose post-construction state cannot be changed. Because of its immutability, he will not have Thread interference
and Memory inconsistent
so on.
Characteristics of Immutable objects:
- Do not set the
setter
method.
- All members are set to
final
+private
- Subclasses are not allowed to override methods. The simple approach is to put the class declaration before the +
final
If there are reference types in the instance variables, do not let them be changed:
Java Basics-Multithreading Basics