Multithreading and parallel programming

Runnable object : It can be understood as a task and is an instance of the Runnable interface.

Thread : The execution process of a task from beginning to end. It is essentially an object that facilitates task execution.

Thread state : Thread state is a stage of the thread life cycle in the operating system.

Process : An application running in memory. Multiple threads can be started in a process.

Task classes generally contain some attributes and methods, which can be used to describe the status and behavior of the task.

Below is an example of defining a task class and creating a thread.

public class Task implements Runnable {
    private String name;
    public Task(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        // 执行任务
        System.out.println("Executing task: " + name);
    }

    public static void main(String[] args) {
        // 创建一个任务
        Task task = new Task("Task 1");
        // 创建一个线程来执行任务
        Thread thread = new Thread(task);
        // 启动线程
        thread.start();
    }
}

After calling the start method, the run method becomes a normal method that Thread will execute by default.

I think the test...

Program error correction

1. forFun The class implements  Runnable the interface, but in  forFun the constructor, it creates a new  forFun object and tries to run it in a new thread. However, this new  forFun object does not implement  Runnable the interface, so it cannot be  Runnable passed to  Thread the constructor as

public class forFun implements Runnable {
    public static void main(String[] args) {
        new forFun();
    }
    public forFun(){
        new Thread(this).start();
    }

    @Override
    public void run() {
        System.out.println("1");
    }
}

In this way, the test will be output 5 times

2. Called start twice

Each thread can only be started once, just delete a start.

What is the purpose of using Platform.runLater ?

Tells the system to run the Runnable object in the application thread.

★Thread status (this must be tested)

  1. New : When a thread is created but has not yet started running, it is in the new state.

  2. Runnable : The thread is ready to run, but may be waiting for CPU scheduling.

  3. Running : The thread is executing on the CPU.

  4. Blocked : The thread is waiting for an event (such as the completion of an I/O operation), so it temporarily stops execution and waits for the event to occur.

  5. Waiting : A thread is waiting for another thread to perform an operation.

  6. Timed Waiting : A thread is waiting for another thread to perform an operation, but there is a time limit.

  7. Terminated : The thread has completed execution or was interrupted by other threads.

        When we create a new thread, it is initially in the new state. Then, when we call the start() method, the thread starts running and enters the Runnable state. If the CPU scheduler chooses to execute this thread, it will enter the running state. If the thread encounters an event that needs to be waited for (such as an I/O operation) during operation, then it will enter the blocked state. When the waiting event is completed, the thread will enter the runnable state again and wait for the selection of the CPU scheduler. If it is actively waiting, it enters the waiting state, waits to be awakened and then enters the Runnable state again. If it is actively sleeping, it enters the time waiting state, and after the sleep time expires, it enters the Runnable state. Note that when the running state is interrupted abnormally or execution is completed, it enters the dead phase.

( Look at the picture to deepen your understanding, the above is my own summary )

What are the benefits of using a thread pool?

The use of thread pools can effectively manage and schedule threads, improve the concurrency performance of the system, and at the same time effectively manage system resources, avoid system resource exhaustion, and improve system stability and responsiveness.

Lock

Divided into two types, synchronized lock and reentrant lock ReentrantLock

1. Synchronization lock

public class LockExample {
    private final Object lock = new Object();

    public void method() {
        synchronized (lock) {
            // 这里是临界区,只有一个线程可以进入
            // 其他线程需要等待这个线程释放锁
        }
    }
}

2. Reentrant lock

 The same thread can acquire this lock multiple times. But you must remember to release the lock in time to avoid deadlock.

import java.util.concurrent.locks.ReentrantLock;

public class LockExample {
    private final ReentrantLock lock = new ReentrantLock();
    public void method() {
        lock.lock();
        try {
            // 这里是临界区,只有一个线程可以进入
            // 其他线程需要等待这个线程释放锁
        } finally {
            lock.unlock();
        }
    }
}

There is another way to describe

1.创建 private static Lock lock=new ReentrantLock();

2. Get lock.lock()

3. Release lock.unlock(); 

4. Create lock condition lock.newCondition()

await() releases the lock and suspends the thread. Once the conditions are met, it will wake up and obtain the lock again.

signal()/signalAll(): Wake up the first Node (or wake up all) in the FIFO queue in condition.await().

Deadlock: A phenomenon in which two or more processes wait for each other due to competition for resources during execution. Without external force, they will not be able to advance.

How to avoid deadlock: Implement resource sorting so that the order of locking of each thread remains the same.

 You should take a test on the procedures for deposits and withdrawals (more on that later)

 The deposit task notifies the withdrawal task whenever the balance changes. When the withdrawal task is awakened, the judgment result of the condition (balance<amount) may still be true. If an if statement is used, the withdrawal task may result in incorrect withdrawals.

The wait() method should be used in a loop, not in an if statement. After modification, wait will be awakened only in abnormal situations.

synchronized(object){
    while(!condition){
        try{
            object.wait();
        }
        catch(InterruptedException ex){
            // 处理异常
        }
    }
}

Buffer class 

 

Read and write in the Buffer class are usually called in a single-threaded environment to ensure the correctness and consistency of data.

When the read method is called, if the queue is empty, the read method will wait until new data can be read.

When the write method is called, if the queue is full, the write method will also block until there is enough space in the queue to store new data.

blocking queue 

(1) Blocking queue: A queue that supports two additional operations that support blocking insertion and removal methods.

Blocking queue is a thread-safe queue access method

When the blocking queue needs to insert elements, if the queue is full, the thread will block until the queue is not full.

When the blocking queue needs to delete elements, if the queue is empty, the thread will block until the queue is not empty.

(2) Blocking queues supported in Java:

ArrayBlockingQueue

LinkedBlockingQueue

PriorityBlockingQueue

 Semaphore

创建:Semaphore semaphore = new Semaphore(3);

Get a semaphore: Semaphore.acquire();

Release a semaphore: Semaphore.release();

A lock can only lock one shared resource, and a semaphore can lock multiple shared resources.

=>Semaphores are used to control access to multiple resources, and locks are used to control access to one resource.

Sync collection

Synchronized collections: Implementing thread-safe Collections.

ArrayList is not synchronized, let it implement synchronizedList to make it synchronized.

 Fork/Join

is an abstract class

Fork/Join framework: Fork splitting and Join merging. Used to perform parallel tasks and divide large problems into sub-problems.

definition:

public abstract class ForkJoinTask<V> implements Future<V>, Serializable{ }

V: Type of result of task execution

Future<V>: Indicates that ForkJoinTask implements the Future interface, so it can be used to obtain task execution results.

RecursiveAction (for tasks that do not return a value) and RecursiveTask (for tasks that return a value) are two subclasses of ForkJoinTask

For fun, ForkPool

RecursiveAction mainTask = new SortTask(list);
ForkJoinPool pool = new ForkJoinPool();
pool.invoke(mainTask);

A sample code that includes a synchronization lock, Synchronized , to start 1000 threads, and each thread adds 1 to the variable sum with an initial value of 0.

import java.util.concurrent.*;
 
public class forFun {
    private Integer sum = new Integer(0);
    public static void main(String[] args) {
        forFun test = new forFun();
        System.out.println("What is sum ? " + test.sum);
    }
 
    public forFun() {
        synchronized(this){//同步代码块,确保只有一个线程可以访问以下代码
            ExecutorService executor = Executors.newFixedThreadPool(1000);//创建大小1000 的线程池
            for (int i = 0; i < 1000; i++) {
                executor.execute(new SumTask());//将SumTask交给线程池
            }
            executor.shutdown();
            while(!executor.isTerminated()) {//等待任务完成
            }
        }
    }
    class SumTask implements Runnable {// 定义一个实现Runnable接口的SumTask类
        public void run() {
            synchronized(this){// 同步代码块,确保只有一个线程可以访问以下代码
                int value = sum.intValue() + 1;
                sum = new Integer(value);
            }
        }
    }
}

Let’s have fun, account deposit/withdrawal tasks

There are thread pools and synchronization locks. lz used to work with his mentor on blockchain and used Solidity to write this kind of thing every day. I felt so kind and happy when I saw it.

import java.util.concurrent.*;

public class forFun {
    private static Account account = new Account();
    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(2); // 创建固定大小为2的线程池
        executor.execute(new DepositTask());
        executor.execute(new WithdrawTask());
        executor.shutdown();
        System.out.println("Deposit Task\t\tWithdraw Task\t\tBalance");
    }

    // 存款任务
    public static class DepositTask implements Runnable {
        public void run() {
            try {
                while (true) {
                    account.deposit((int) (Math.random() * 10) + 1);
                    Thread.sleep(1000);
                }
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            }
        }
    }

    // 取款任务
    public static class WithdrawTask implements Runnable {
        public void run() {
            while (true) {
                account.withdraw((int) (Math.random() * 10) + 1);
            }
        }
    }

    // 账户类
    public static class Account {
        private int balance = 0;

        // 获取账户余额
        public int getBalance() {
            return balance;
        }

        // 存款方法,使用 synchronized 保证线程安全
        public synchronized void deposit(int amount) {
            balance += amount;
            System.out.println("Deposit " + amount +
                    "\t\t\t\t\t" + getBalance());
            notifyAll(); // 唤醒其他等待线程
        }

        // 取款方法,使用 synchronized 保证线程安全
        public synchronized void withdraw(int amount) {
            try {
                while (balance < amount)  // 当余额不足时,进入等待状态
                    wait();
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            }

            balance -= amount;
            System.out.println("\t\t\tWithdraw " + amount +
                    "\t\t" + getBalance());
        }
    }
}

Guess you like

Origin blog.csdn.net/mynameispy/article/details/135306516