1. The concept of process and thread
(1) In traditional operating systems, programs cannot run independently, and as the basic units of resource allocation and independent operation are all processes.
In systems without OS, the execution method of programs is sequential execution, that is, one program must be executed before another program can be executed; in a multi-program environment, multiple programs are allowed to be executed concurrently. There are significant differences between the two ways of execution of a program. It is precisely this characteristic of the concurrent execution of programs that leads to the introduction of the concept of processes in the operating system.
Since people proposed the concept of processes in the 1960s, processes have always been used in OS as the basic unit that can have resources and run independently. Until the mid-1980s, people proposed a basic unit that can run independently, threads, which is smaller than processes, to try to use it to increase the degree of concurrent execution of programs within the system, thereby further increasing the system's throughput. Especially after entering the 1990s, multi-processor systems have developed rapidly. Threads can better improve the parallel execution of programs than processes and fully exert the advantages of multi-processors. Therefore, threads have been introduced in the multi-processor OS launched in recent years to improve the performance of OS.
―The above is excerpted from "Computer Operating System - Edited by Tang Xiaodan and others - Edition 3" (Download address)
(2) The following figure is an explanation from Zhihu users:
Through the above general understanding, we basically know what threads and processes do. So let’s summarize the concept for processes and threads below:
(3) Process is a running activity of a program in a computer about a certain data set, it is the basic unit of the system's resource allocation and scheduling, and it is the basis of the operating system structure. In the early process-oriented computer structures, processes were the basic execution entities of programs; in the contemporary thread-oriented computer structures, processes were containers of threads. A program is a description of instructions, data and its organizational form, and a process is an entity of a program.
(4) Threads, sometimes called lightweight processes (LWP), are the smallest unit of program execution flow. Threads are a single sequential control process in a program. A relatively independent and scheduleable execution unit in the process is the basic unit of independent scheduling and dispatching CPU in the system, which refers to the scheduling unit of running programs. Running multiple threads simultaneously in a single program to complete different work, called multithreading.
(5) The relationship between process and thread:
2. Java implements multi-threading method
(1) Inherit Thread and rewrite the run() method
public class MyThread extends Thread { @Override public void run() { while (true) { System.out.println(this.currentThread().getName()); } } public static void main(String[] args) { MyThread thread = new MyThread(); thread.start(); //The correct way to start thread}}Output result:
Thread-0Thread-0Thread-0...
In addition, you need to understand that the start() method is the start() method instead of the run() method. If the run() method is used, then it is an ordinary method to execute.
(2) Implement the Runable interface
public class MyRunnable implements Runnable { @Override public void run() { System.out.println("123"); } public static void main(String[] args) { MyRunnable myRunnable = new MyRunnable(); Thread thread = new Thread(myRunnable, "t1"); thread.start(); }}3. Thread safety
Thread safety concept: When multiple threads access a certain class (object or method), the class can always show the correct behavior, and then this class (object or method) is thread-safe.
Thread safety is when accessing multi-threads, a locking mechanism is adopted. When a thread accesses a certain data of the class, it is protected. Other threads cannot access it until the thread has finished reading it, and other threads can not use it. There will be no data inconsistency or data pollution. Threads are not safe, which means that data access protection is not provided. It is possible that multiple threads may change the data one after another, resulting in the resulting data being dirty. The common locking mechanism here is: synchronized
4. Synchronized modifier
(1) synchronized: You can add locks to any object and method, and the locked code is called a "mutex area" or "critical area".
(2) **Do not use **synchronized instance (code A):
public class MyThread extends Thread {private int count = 5;@Override public void run() {count--;System.out.println(this.currentThread().getName() + " count:" + count);}public static void main(String[] args) {MyThread myThread = new MyThread();Thread thread1 = new Thread(myThread, "thread1");Thread thread2 = new Thread(myThread, "thread2");Thread thread3 = new Thread(myThread, "thread3");Thread thread4 = new Thread(myThread, "thread4");Thread thread5 = new Thread(myThread, "thread5");thread1.start();thread2.start();thread3.start();thread4.start();thread5.start();}}One result of the output is as follows:
thread3 count:2thread4 count:1thread1 count:2thread2 count:3thread5 count:0
It can be seen that the above result is incorrect, because multiple threads operate the run() method at the same time and modify the count, which in turn causes an error.
(3) **Use **synchronized instance (code B):
public class MyThread extends Thread { private int count = 5; @Override public synchronized void run() { count--; System.out.println(this.currentThread().getName() + " count:" + count); } public static void main(String[] args) { MyThread myThread = new MyThread(); Thread thread1 = new Thread(myThread, "thread1"); Thread thread2 = new Thread(myThread, "thread2"); Thread thread3 = new Thread(myThread, "thread3"); Thread thread4 = new Thread(myThread, "thread4"); Thread thread5 = new Thread(myThread, "thread5"); thread1.start(); thread2.start(); thread3.start(); thread4.start(); thread5.start(); }}Output result:
thread1 count:4thread2 count:3thread3 count:2thread5 count:1thread4 count:0
It can be seen that the difference between code A and code B is that synchronized modification is added to the run() method.
The description is as follows:
When multiple threads access the MyThread run method, if synchronized modification is used, the multi-thread will be processed in a queue (the queue here is determined according to the order of CPU allocation). If a thread wants to execute the code in the synchronized modification method, it first tries to obtain the lock. If it gets the lock, executes the contents of the synchronized code body. If it cannot get the lock, the thread will continue to try to obtain the lock until it gets it. Moreover, multiple threads compete for the lock at the same time, which means that lock competition will occur.
5. An object has a lock! Multiple threads and multiple locks!
What is, one object has one lock, multiple threads have multiple locks! First, let’s take a look at the example code below (code C):
public class MultiThread { private int num = 200; public synchronized void printNum(String threadName, String tag) { if (tag.equals("a")) { num = num - 100; System.out.println(threadName + " tag a,set num over!"); } else { num = num - 200; System.out.println(threadName + " tag " + tag + ", num = " + num); } public static void main(String[] args) throws InterruptedException { final MultiThread multiThread1 = new MultiThread(); final MultiThread multiThread2 = new MultiThread(); new Thread(new Runnable() { public void run() { multiThread1.printNum("thread1", "a"); } }).start(); Thread.sleep(5000); System.out.println("Wait 5 seconds to make sure thread1 has been executed!"); new Thread(new Runnable() { public void run() { multiThread2.printNum("thread2", "b"); } }).start(); }}Output result:
thread1 tag a,set num over!thread1 tag a, num = 100Wait 5 seconds to make sure thread1 has been executed! thread2 tag b,set num over!thread2 tag b, num = 0
It can be seen that there are two objects: multiThread1 and multiThread2. If multiple objects use the same lock, the result of the above execution should be: thread2 tag b, num = -100. Therefore, each object has the lock of that object.
The locks obtained by the keyword synchronized are object locks, rather than treating a piece of code or method as locks. Therefore, in the above example code C, which thread first executes the synchronized keyword method, the thread holds the lock of the object to which the method belongs. The thread obtains two different locks of two different objects, and they complement each other.
So, in normal scenarios, there must be a situation where all objects will operate on a variable count, so how to implement it? It is very simple to add static. We know that all objects in this class have the same reference, no matter how many objects are instantiated, the call is a method, and the code is as follows (code D):
public class MultiThread { private static int num = 200; public static synchronized void printNum(String threadName, String tag) { if (tag.equals("a")) { num = num - 100; System.out.println(threadName + " tag a,set num over!"); } else { num = num - 200; System.out.println(threadName + " tag b,set num over!"); } System.out.println(threadName + " tag " + tag + ", num = " + num); } public static void main(String[] args) throws InterruptedException { final MultiThread multiThread1 = new MultiThread(); final MultiThread multiThread2 = new MultiThread(); new Thread(new Runnable() { public void run() { multiThread1.printNum("thread1", "a"); } }).start(); Thread.sleep(5000); System.out.println("Wait 5 seconds to make sure thread1 has been executed!"); new Thread(new Runnable() { public void run() { multiThread2.printNum("thread2", "b"); } }).start(); }}Output result:
thread1 tag a,set num over!thread1 tag a, num = 100Wait 5 seconds to make sure thread1 has been executed! thread2 tag b,set num over!thread2 tag b, num = -100
It can be seen that adding static modification to variables and methods can realize the scenarios we need. It also shows that for non-static static modification methods or variables, a locked object.
6. Synchronous and asynchronous object locks
(1) Synchronized
The concept of synchronization is sharing. We need to know that the word "sharing" is not a shared resource, there is no need to synchronize, that is, there is no need to lock it;
The purpose of synchronization is to ensure the safety of threads. In fact, for thread safety, two most basic characteristics need to be met: atomicity and visibility;
(2) Asynchronized: asynchronized
The concept of asynchronousness is independence, without any constraints between each other, and there is no relationship between the two.
(3) Sample code:
public class MyObject { public void method() { System.out.println(Thread.currentThread().getName()); } public static void main(String[] args) { final MyObject myObject = new MyObject(); Thread t1 = new Thread(new Runnable() { public void run() { myObject.method(); } }, "t1"); Thread t2 = new Thread(new Runnable() { public void run() { myObject.method(); } }, "t2"); t1.start(); t2.start(); }}In the above code, method() is an asynchronous method.
Summarize
The above is the entire content of this article about the initial solution to the concept of threading, process and Synchronized in Java multi-threading. I hope it will be helpful to everyone. If there are any shortcomings, please leave a message and point it out, and the editor will reply to everyone in time.