Java multi-thread programming - detailed explanation

Java multi-threaded programming is a very important topic in Java development, which allows programmers to take full advantage of the multi-core processors of modern computers, improving the performance and response speed of programs. This article will introduce the basics of multithreaded programming in Java, and demonstrate how to use Java multithreaded programming through sample code.

1. What is Java multithreaded programming?

        Before we start explaining Java multithreaded programming, we need to understand some basic concepts.

1.1 The difference between process and thread

        A process is an independent execution unit running on an operating system, and each process has its own address space, stack, and data segment.

        A thread is an executable entity within a process and the smallest unit of program execution.

        All threads within the same process share the same address space and data segment, but each thread has its own stack. Therefore, threads are lighter-weight and more flexible than processes.

1.2 Implementation of Java threads

        In Java, threads are implemented in two ways:

  • Inherit the Thread class
  • Implement the Runnable interface

        These two methods can create threads, but it is recommended to use the method of implementing the Runnable interface to create threads, because it can avoid the limitations caused by Java's single inheritance mechanism, and can better integrate with the thread pool.

1.3 The life cycle of threads

        In Java, each thread has its own life cycle, which consists of five states of the thread:

  • New state (New): When a Thread object is created, it is in the new state.
  • Ready state (Runnable): When the start method of the thread object is called, it enters the ready state. At this point, it is ready to run, but has not yet been allocated a CPU time slice.
  • Running state (Running): When a thread gets a CPU time slice and starts executing, it enters the running state.
  • Blocked state (Blocked): When a thread suspends execution, it enters the blocked state. For example, when a thread is waiting for a resource, it enters the blocked state.
  • Terminated state: After a thread finishes executing its run method, it enters the terminated state.

2. Java multithreading implementation

        In Java, there are two ways to implement multithreading:

2.1 Inheriting the Thread class

        By inheriting the Thread class, you can create a thread class and override the run() method to define the execution logic of the thread in this method.

        For example:

// 继承Thread类
public class MyThread extends Thread {

    @Override
    public void run() {
        // 线程执行的代码
    }

}

2.2 Implement the Runnable interface

        Implementing the Runnable interface can create a thread class and implement the run() method, in which the execution logic of the thread is defined.

        For example:

// 实现Runnable接口
public class MyRunnable implements Runnable {

    @Override
    public void run() {
        // 线程执行的代码
    }

}

2.3. Start thread

        In Java, to start a thread, you must use the start() method. This method calls the thread's run() method and executes the method in a new thread.

        For example:

// 启动线程
MyThread thread = new MyThread();   // 创建线程
thread.start();                     // 启动线程

2.4. Thread priority

        In Java, a thread can set a priority. By setting the priority of a thread, you can control the priority of the thread when competing for CPU resources. The priority range is from 1 to 10. The larger the number, the higher the priority. Java default thread priority is 5.

Thread thread = new MyThread();
thread.setPriority(Thread.MAX_PRIORITY); //设置线程优先级
thread.start();

2.5. Thread synchronization

        In Java multithreaded programming, thread synchronization is very important. Thread synchronization can prevent multiple threads from accessing shared data at the same time, thereby avoiding data anomalies. Java provides many thread synchronization mechanisms, among which the synchronized keyword and the Lock interface are more commonly used.

The synchronized keyword can be used to modify a method or code block. When a thread accesses a method or code block modified by the synchronized keyword, other threads will be blocked until the current thread finishes executing.

        For example:

public class Counter {
    private int count = 0;
    
    public synchronized void increment() {
        count++;
    }
    
    public int getCount() {
        return count;
    }
}

public class IncrementThread extends Thread {
    private Counter counter;
    
    public IncrementThread(Counter counter) {
        this.counter = counter;
    }
    
    public void run() {
        for (int i = 0; i < 100000; i++) {
            counter.increment();
        }
    }
}

public class Main {
    public static void main(String[] args) throws InterruptedException {
        Counter counter = new Counter();
        IncrementThread thread1 = new IncrementThread(counter);
        IncrementThread thread2 = new IncrementThread(counter);
        
        thread1.start();
        thread2.start();
        
        thread1.join();
        thread2.join();
        
        System.out.println("Counter: " + counter.getCount());
    }
}

        In the above code, we have created a Counter class to store the value of the counter and marked the increment() method as a synchronized method using the synchronized keyword.

        Then, we create two IncrementThread instances and pass them to the same Counter instance. In the main() method, we start the two threads and wait for them to complete using the join() method. Finally, we output the value of the counter.


The Lock interface is another thread synchronization mechanism provided by Java, which can control thread synchronization more flexibly. Thread synchronization can be achieved by calling the lock() method and unlock() method of the Lock interface.

        For example:

Lock lock = new ReentrantLock();
lock.lock();
//需要同步的代码
lock.unlock();

2.6. Thread exception handling

        In multi-threaded programming, threads may generate exceptions due to various reasons (such as accessing non-existing resources, unable to acquire resource locks, etc.), and these exceptions need to be handled to prevent the program from crashing.

        In Java, thread exceptions can be caught and processed through the try-catch statement.


3. Thread pool and inter-thread communication

3.1. Thread pool

        A thread pool is a reusable collection of threads that can manage and execute multiple tasks. The Executor framework in Java provides the ThreadPoolExecutor class to implement the thread pool.

        The advantages of thread pools include:

  1. Reuse threads to reduce the overhead of thread creation and destruction.
  2. Control the number of concurrency to avoid excessive occupation of system resources.
  3. Provide a unified task management and scheduling mechanism to facilitate the realization of task priority, timeout and other functions.

Here is a simple thread pool example:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Main {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(5); // 创建一个固定大小的线程池

        for (int i = 0; i < 10; i++) {
            Runnable worker = new WorkerThread("Task " + i);
            executor.execute(worker); // 提交任务给线程池
        }

        executor.shutdown(); // 关闭线程池
        while (!executor.isTerminated()) {} // 等待所有任务完成

        System.out.println("All tasks are finished.");
    }
}

class WorkerThread implements Runnable {
    private String task;

    public WorkerThread(String task) {
        this.task = task;
    }

    public void run() {
        System.out.println(Thread.currentThread().getName() + " is processing " + task);
        try {
            Thread.sleep(1000); // 模拟执行任务需要的时间
        } catch (InterruptedException e) {}
        System.out.println(Thread.currentThread().getName() + " has finished " + task);
    }
}

        In the above code, we created a thread pool with a fixed size of 5, and submitted 10 tasks to the thread pool. Each task is a WorkerThread instance that will print its own task name and simulate how long it takes to execute. When all tasks are done, we close the thread pool and print a message.

3.2. Inter-thread communication

        Inter-thread communication refers to the process of information transfer between multiple threads by sharing resources. Java provides two mechanisms to achieve inter-thread communication: wait/notify and BlockingQueue.

        The following is an example of inter-thread communication using the wait/notify mechanism:

public class Message {
    private String message;
    private boolean empty = true;
    
    public synchronized String read() {
        while (empty) { // 如果消息队列为空,则等待直到有新消息
            try {
                wait();
            } catch (InterruptedException e) {}
        }
        
        empty = true; // 标记消息队列为空
        notifyAll(); // 唤醒所有等待的线程
        
        return message;
    }
    
    public synchronized void write(String message) {
        while (!empty) { // 如果消息队列已满,则等待直到有空位
            try {
                wait();
            } catch (InterruptedException e) {}
        }
        
        empty = false; // 标记消息队列不为空
        this.message = message;
        notifyAll(); // 唤醒所有等待的线程
    }
}

public class ReaderThread extends Thread {
    private Message message;
    
    public ReaderThread(Message message) {
        this.message = message;
    }
    
    public void run() {
        String msg = message.read();
        System.out.println("ReaderThread got message: " + msg);
    }
}

public class WriterThread extends Thread {
    private Message message;
    
    public WriterThread(Message message) {
        this.message = message;
    }
    
    public void run() {
        message.write("Hello World!");
    }
}

public class Main {
    public static void main(String[] args) {
        Message message = new Message();
        
        ReaderThread readerThread1 = new ReaderThread(message);
        ReaderThread readerThread2 = new ReaderThread(message);
        WriterThread writerThread = new WriterThread(message);
        
        readerThread1.start();
        readerThread2.start();
        writerThread.start();
    }
}

        In the above code, we create a Message class to store messages, and use the wait/notify mechanism to implement inter-thread communication. In ReaderThread, we read messages using read() method, and in WriterThread, we write messages using write() method.

Summarize

        Java multi-thread programming is a very important topic in Java development. This article introduces some key concepts and technologies in Java multi-thread programming, including threads and processes, thread creation, thread synchronization, thread pool and inter-thread communication. By learning Java multi-threaded programming, you can make the program more efficient, stable and scalable.

Guess you like

Origin blog.csdn.net/qq_63029994/article/details/130583872
Recommended