Java multi-threading operation mechanism
Creation of Java multithreading
There are three ways to create Java multi-threads:
1. Create a process by inheriting the Thread class
2. Create a thread through the Runnable interface
3. Create a thread through the Callable interface and Future interface
1. Create a process by inheriting the Thread class
- Step 1: Create a subclass, rewrite
run()
the method of the class, and implement the function of the thread - Step 2: Create an instance of the Thread subclass, that is, create a process object
- Step 3: Call
start()
the method of the thread object to start the thread
Thread common methods
method | illustrate |
---|---|
void run() | The code executed when the thread is running |
void interript | Interrupt process |
void start() | Cause the thread to start executing |
static void yield() | Pause the currently executing process and execute other processes |
Thread.State getState() | Returns the status of this thread |
final boolean isAlive() | Test whether the thread is active |
String getName() | Returns the name of this thread |
void setName(String name) | Change thread name |
public class www {
public static void main(String[] args){
for (int i = 0; i < 3; i++) {
Test test = new Test(i);
test.start();
}
}
}
class Test extends Thread{
int name;
public Test(int name){
this.name = name;
}
public void run() {
System.out.println("线程"+name);
}
}
The output results may be different each time because the execution progress of the sub-threads is uncertain and they run concurrently.
Disadvantage: If the class already inherits a class, it cannot inherit Thread
the class.
2. Create threads through Runnable interface
- Step 1: Define
Runnable
the implementation class of the interface and implement the methods of the interfacerun()
- Step 2: Define
Runnable
an instance of the implementation class, and use this instance as a parameterThread
of the classtarget
to createThread
a thread object. ThisThread
object is the real thread object.
public class www {
public static void main(String[] args){
for (int i = 0; i < 3; i++) {
Test test = new Test(i);
Thread t = new Thread(test);
t.start();
}
}
}
class Test implements Runnable{
int name;
public Test(int name){
this.name = name;
}
public void run() {
System.out.println("线程"+name);
}
}
Similarly, the output results may be different each time. This is also because the execution progress of the sub-threads is uncertain and they run concurrently.
3. Create threads through Callable interface and Future interface
- Step 1: Create
Callable
an implementation class of the interface and implementcall()
the method, which will serve as the execution body of the thread and have a return value. - Step 2: Create
Callable
an instance of the implementation class and useFutureTask
the class to wrapCallable
the object thatFutureTask
encapsulates the return value of theCallable
object'scall()
method. - Step 3: Using
FutureTask
the object asThread
objecttarget
, create and start a new thread. - Step 4: Call the method
FutureTask
of the objectget()
to obtain the return value when the sub-thread execution ends.
public class www {
public static void main(String[] args){
for (int i = 0 ; i < 3 ; i++){
Test test = new Test(i);
//使用FutureTask来包装Callable对象
FutureTask result = new FutureTask(test);
//创建线程对象
Thread thread = new Thread(result);
//启动线程
thread.start();
}
}
}
class Test implements Callable{
int name;
public Test(int name){
this.name = name;
}
@Override
public Object call() throws Exception {
System.out.println("线程"+name);
return null;
}
}
Similarly, the output results may be different each time. This is also because the execution progress of the sub-threads is uncertain and they run concurrently.
Java thread life cycle
It is divided into six states, specifically the creation (New) state, the runnable (Runnable) state, the blocked (Blocked) state (Bu Lao Kete), the waiting state (Waiting) state, the timed waiting state (Timed waiting) state, and the terminated (Terminated) state. ) status.
Java thread scheduling
Thread sleep——Sleep
You can pause the currently executing thread for a period of time
public class www extends JFrame implements Runnable {
JLabel jLabel1,jLabel2;
public www (){
jLabel1 = new JLabel("当前时间:");
jLabel2 = new JLabel();
Container containerPane = this.getContentPane();
containerPane.setLayout(new FlowLayout());
this.add(jLabel1);
this.add(jLabel2);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setSize(300,200);
this.setVisible(true);
}
@Override
public void run() {
while (true){
jLabel2.setText(getTime());
//获取当前进程 并延时2000ms
try {
Thread.currentThread().sleep(2000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
String getTime(){
Date date =new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年MM月dd日HH:mm:ss Z");
return simpleDateFormat.format(date);
}
public static void main(String[] args) {
www test1 = new www();
Thread thread1 = new Thread(test1);
thread1.start();
}
}
It can be seen that the time is refreshed every 2S (2000ms)
Thread concession - yield (youde)
yield()
Both sleep()
will suspend the execution of the current process. The difference is that it yield()
will first determine whether there is a process with the same or higher priority than the process. If there is, it will stop and let the same or higher priority process run first. If there is no process, the process will continue to run.
public class www implements Runnable {
String str = "";
@Override
public void run() {
for (int i = 1; i <= 9; i++) {
str += Thread.currentThread().getName() + "----" + i + " ";
if(i%3 == 0){
System.out.println(str);
str = "";
Thread.currentThread().yield();
}
}
}
public static void main(String[] args) {
www test1 = new www();
www test2 = new www();
Thread thread1 = new Thread(test1,"线程1");
Thread thread2 = new Thread(test2,"线程2");
thread1.start();
thread2.start();
}
}
The output result threads are alternate, and the output results may not be alternate and different every time it is run, so the execution method of controlling the thread through yield() is unreliable.
Thread collaboration-join
If a thread reaches a certain point and waits for another thread to finish before it can continue to run, this situation can be achieved by calling the join() method of another thread.
public class www {
public static void main(String[] args) {
Thread thread = new test();
thread.start();
for (int i = 1; i <= 10; i++) {
System.out.println("主线程");
if(i == 5){
try {
thread.join();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
}
class test extends Thread{
public void run(){
for (int i = 1; i <= 10 ; i++) {
System.out.println("子线程");
}
}
}
join()
Normally, the main thread creates and starts the thread. If the sub-thread takes a lot of time to run, the main thread often finishes running earlier than the sub-thread. This example is to set the status to wait for the sub-thread to run before the main thread finishes running. Finish and then continue running.
process priority
Each process in Java has a corresponding priority, and those with higher priorities get more running opportunities. Thread priority is usually represented by a number between 1 and 10. The larger the number, the higher the priority. The default thread level is 5.
Three constants are defined in the Thread class
name | value |
---|---|
MIN_PRIORITY | 1 |
MAX_PRIORITY | 10 |
NORM_PRIORITY | 5 |
Priority setting setPrioriy()
methods and methods of obtaining prioritygetPrioriy()
daemon
Java is divided into two categories 用户线程
and守护线程
Daemon threads are also called background threads that provide services to other threads. Such threads can monitor the running dependencies of other threads and other threads.
The user thread is a general thread responsible for business logic
You can use setDaemon()
the method to set the type of a thread to true. The daemon thread can only 线程.start()
be called before. You can also use isDaemon()
the method to determine whether the process is a daemon process.
Thread synchronization
Problems caused by multi-threading: When designing multi-threading, sometimes multiple threads need to share a part of the code block to achieve the purpose of sharing a private member variable or static member of the class. At this time, because threads compete with each other for CPU resources, threads access these shared resources out of order, and ultimately correct results may not be obtained. These problems are often called thread safety problems.
For example:
public class www {
public static void main(String[] args) {
test test = new test();
for (int i = 0; i < 10; i++) {
new Thread(test).start();
}
}
}
class test implements Runnable{
public int num = 0;
//使用temp是为了增加线程的切换几率
private void add(){
int temp;
for (int i = 0; i < 1000; i++) {
temp = num;
temp++;
num = temp;
}
System.out.println(Thread.currentThread().getName() + " "+ num);
}
public void run(){
add();
}
}
The output results are almost never correct in multiples of 1000. This is due to the concurrent execution of multi-threads and the simultaneous num
modification of variables by multiple threads. To solve this problem, Java's synchronization mechanism is necessary.
synchronized code block
Java is equipped with a lock and a waiting set for each object. This object can be an instance object or a class object. Locking the instance object can ensure that threads related to the instance object can use the object lock mutually exclusive; locking the class object can ensure that the threads related to the class can use the class object lock mutually. Create an instance object through the new keyword to obtain a reference to the object. To obtain a reference to the class object. We can pass forName
member methods. The static member variables and static member methods of a class belong to the class object, while the non-static member variables and non-static member methods of a class belong to the instance object of the class.
synchronize(synObject){
//关键code
}
When the process enters the critical code, the system will first check whether the object's lock has been acquired by other threads. If not, the JVM will hand over the object's lock to the process currently requesting the lock. After the thread acquires the lock, it can enter the critical code area.
For example:
public class www {
public static void main(String[] args) {
test test = new test();
for (int i = 0; i < 10; i++) {
new Thread(test).start();
}
}
}
class test implements Runnable{
int num = 0;
private void add(){
int temp;
for (int i = 0; i < 1000; i++) {
temp = num;
temp++;
num = temp;
}
System.out.println(Thread.currentThread().getName() + " "+ num);
}
public void run(){
synchronized (this){
add();
}
}
}
In this way, the result of each thread's execution is an integer.
Modify the add() method with synchronized to get the same result. This is the synchronization method discussed below.
private synchronized void add(){
int temp;
for (int i = 0; i < 1000; i++) {
temp = num;
temp++;
num = temp;
}
System.out.println(Thread.currentThread().getName() + " "+ num);
}
sync method
Synchronized methods, like synchronized code blocks, use interlocking to achieve code synchronization access.
public class www {
public static void main(String[] args) {
test test = new test();
for (int i = 0; i < 10; i++) {
new Thread(test).start();
}
}
}
class test implements Runnable{
int num = 0;
private synchronized void add(){
int temp;
for (int i = 0; i < 1000; i++) {
temp = num;
temp++;
num = temp;
}
System.out.println(Thread.currentThread().getName() + " "+ num);
}
public void run(){
add();
}
}
Synchronization is a high-cost operation, so try to avoid using synchronize
synchronization methods with large settings. Under normal circumstances, use synchronize
code blocks to synchronize key codes.
Thread communication
Sometimes multi-threads have order problems during execution. Java provides three methods to solve thread communication problems. wait()
They are , notify()
, methods respectively notifyAll()
. These three keywords can only work within the scope of the synchronized keyword, and they have practical significance only when paired with these three methods in the same method.
wait()
Method: The thread calling this method can release the lock of the shared resource and enter the waiting state from the runnable state. Know to be awakened again.
notify()
Method: You can wake up the first thread in the waiting queue waiting for the same shared resource, and make the process exit the waiting state and enter the runnable state.
notifyAll()
Method: All processes that are waiting for the same shared resource in the waiting queue can exit from the waiting state and enter the runnable state. If there are multiple processes, whichever one has the highest priority will run first. Use this method when you don't know which process to wake up.
Supplementary knowledge points:
Detailed explanation of the five states of threads
Here's an example:
public class www {
public static void main(String[] args) {
//实例化一个ShareStore对象 并创建进程启动
ShareStore shareStore = new ShareStore();
new Consumer(shareStore).start();
new Producer(shareStore).start();
}
}
/***
* 生产者
*/
class Producer extends Thread{
private ShareStore shareStore;
Producer(ShareStore shareStore){
this.shareStore = shareStore;
}
@Override
public void run() {
int num = 1;
while (true){
shareStore.setShareNum(++num);
System.out.println("Producer生产了一个数字"+num);
//睡眠1s
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
/***
* 消费者
*/
class Consumer extends Thread{
private ShareStore shareStore;
Consumer(ShareStore shareStore){
this.shareStore = shareStore;
}
@Override
public void run() {
int num = 1;
while (true){
num = shareStore.getShareNum();
System.out.println("Consumer消费了一个数字"+num);
//睡眠1s
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
/***
* 用来管理的
*/
class ShareStore{
private int num;
private boolean writeable = true;
public synchronized void setShareNum(int num){
if (!writeable){
try {
wait();//等待消费者消费完成
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
this.num = num;
writeable = false;
notify(); //通知消费者 生产者已经生产可以消费
}
public synchronized int getShareNum(){
if (writeable){
try {
wait(); //等待生产者生产出来
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
writeable = true;
notify();//通知可以生产
return this.num;
}
}
The output results are that the producer first produces a number, and the consumer then consumes it.
deadlock
Deadlock is a scenario: when two or more processes form a single-waiting ring, each process is waiting for each other's resource release, and neither of them can execute and continues to form a deadlock.