Talk about multithreading

Keywords: Programming Java

I. progress

Concept:

A process is a running program, which represents the memory area occupied by the program. For example: 360 is a program, and there are many processes running when 360 is running, as shown below.

Characteristic:

  • Independence: a process is an independent entity in the system. It can have its own independent resources and its own private address space. Without the consent of the thread itself, other threads cannot directly access this thread.
  • Dynamic: the difference between a process and a program is that a program is only a static set of instructions, while a process is a set of instructions that are active in the system, and a process adds the concept of time. A process has its own life cycle and various states, which are not available in the process.
  • Concurrency: multiple processes can execute concurrently on a single processor, and multiple processes will not affect each other.

Time slice:

Time slice is the time that CPU allocates to each program. Each process is allocated a time period, which is called its time slice. That is, the time allowed for the process to run, so that the various programs are carried out at the same time from the surface.
 
If the process is still running at the end of the timeslice, the CPU is stripped and assigned to another process, suspending the current process. If the process is blocked or ended before the end of the timeslice, the CPU will switch immediately without wasting CPU resources. When you switch to the previously executed process, restore the site and continue execution.
 
On the macro level: we can open multiple applications at the same time, and each program runs in parallel at the same time. 1/3000ns
 
At the micro level: because there is only one CPU, only one part of the program requirements can be processed at a time. How to deal with fairness? One way is to introduce a time slice, and each program executes in turn. Multicore improves concurrency.

Two, thread

Concept:

Thread is the smallest unit that the system can schedule operations
It is included in the process. A process can have multiple threads, which is the actual operation unit of the process
Multithreading extends the concept of multiprocess, so that the same process can simultaneously process multiple tasks.
In short, a program runs at least one process, and a process contains one thread (single thread) or multiple threads.

Relationship between process and thread

From the above figure, we can see that there can be multiple processes in an operating system and multiple threads in a process.
 
Each process has its own independent memory, each thread shares the memory in a process, and each thread has its own independent memory. It's very important to remember this relationship
 
So if you want to use thread technology, you need to have a process first. The process creation is created by OS. Can you implement it? No, it's usually done in c or c + +.

3, Features of multithreading

Randomness

Thread state

There are five states in the thread life cycle:

  1. New: when a thread object pair is created, it enters the new state, for example: Thread t = new MyThread();

  2. Runnable: when the start() method (t.start();) of the thread object is called, the thread enters the ready state. A ready thread just means that it is ready to wait for the CPU to schedule execution at any time, not that it will execute immediately after executing t.start();

  3. Running: when the CPU starts to schedule the ready threads, the threads can actually execute, that is, enter the running state. Note: the ready state is the only entry to the running state, that is to say, if a thread wants to enter the running state for execution, it must be in the ready state first;

  4. Blocked: for some reason, a thread in the running state temporarily gives up the right to use the CPU and stops executing. At this time, it enters the blocked state. Until it enters the ready state, it has the chance to be called by the CPU again to enter the running state;

  5. According to the different causes of blocking, the blocking state can be divided into three types:
    a) Waiting for blocking: the thread in the running state executes the wait() method to make the thread enter the waiting blocking state;
    b) Synchronization blocking: when a thread fails to acquire the synchronized synchronization lock (because the lock is occupied by other threads), it will enter the synchronization blocking state;
    c) Other blocking: when a thread's sleep() or join() is called or an I/O request is issued, the thread will enter a blocking state. When the sleep () state, the join () wait for the thread to terminate or time out, or the I/O processing is completed, the thread will return to the ready state.

  6. Dead: the thread finishes executing or exits the run() method due to an exception, and the thread ends its life cycle.

4, Multithreading creation

Inherit Thread:

The Thread class essentially implements an instance of the Runnable interface, representing an instance of a Thread. The only way to start a Thread is through the start() instance method of the Thread class. The start () method is a native method, which will notify the underlying operating system, and finally the operating system will start a new Thread, and the operating system will execute the run () method. It's very simple to implement multithreading in this way. You can start a new Thread and execute the self-defined run() method by directly extending the Thread with your own class and copying the run() method. The simulation opens multiple threads, each calling the run () method.

To implement the Runnable interface:

If your own class already extends another class, you cannot inherit more. At this time, you can implement a Runnable interface.


Comparison:

mode Advantage shortcoming
Thread It is easy to write. If you need to access the current thread, you don't need to use the Thread.currentThread() method. You can get the current thread by using this directly. Thread class already inherits thread class, so it can no longer inherit other parent classes
Runnable Thread class only implements Runnable interface or Callable interface, and can inherit other classes. In this way, multiple threads can share the same target object, so it is very suitable for multiple threads to handle the same resource, so it can separate the CPU, code and data, form a clear model, and better reflect the idea of object-oriented. Programming is a little more complex, and if you want to access the current thread, you must use the Thread.currentThread() method.


Ticket sales:

Inheriting Thread

public class TestThread {

	public static void main(String[] args) {

		Ticket t1 = new Ticket("one");
		Ticket t2 = new Ticket("two");
		Ticket t3 = new Ticket("three");
		Ticket t4 = new Ticket("four");
		t1.start();
		t2.start();
		t3.start();
		t4.start();

	}
}

class Ticket extends Thread {
	static int tickets = 100;

	Ticket(String name) {
		super(name);
	}

	public void run() {
		while (true) {

			// 1. In multithreading, data is unsafe -- the reason is: the characteristics of multithreading randomness + access delay
			// 2. Question: sell the same ticket repeatedly + sell the negative ticket

			// When tickets = 1, t1,t2,t3,t4 can work
			if (tickets > 0) {

				// t1,t2,t3,t4 sleep when tickets = 1
				try {
					sleep(100);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				// When tickets = 1, t1 wakes up first, outputs 1, and tickets becomes 0
				// When tickets = 2, t1 wakes up first, outputs 0, and tickets becomes - 1
				// When tickets = 3, t1 wakes up first, outputs - 1, and tickets changes to - 2
				// When tickets = 4, t1 wakes up first, outputs - 2, and tickets changes to - 3

				// The same data situation: when the thread tickets has not been output, another thread comes to work
				System.out.println(getName() + "Ticket number:" + tickets--);
			} else {
				break;
			}
		}
	}
}

Implement Runnable

public class TestThread2 {

	public static void main(String[] args) {

		Ticket2 t = new Ticket2();

		Thread t1 = new Thread(t, "one");
		Thread t2 = new Thread(t, "two");
		Thread t3 = new Thread(t, "three");
		Thread t4 = new Thread(t, "four");
		t1.start();
		t2.start();
		t3.start();
		t4.start();

	}
}

class Ticket2 implements Runnable {
	int tickets = 100;

	public void run() {
		while (true) {

			// 1. In multithreading, data is unsafe -- the reason is: the characteristics of multithreading randomness + access delay
			// 2. Question: sell the same ticket repeatedly + sell the negative ticket

			// When tickets = 1, t1,t2,t3,t4 can work in java.lang
			if (tickets > 0) {

				// t1,t2,t3,t4 sleep when tickets = 1
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				// When tickets = 1, t1 wakes up first, outputs 1, and tickets becomes 0
				// When tickets = 2, t1 wakes up first, outputs 0, and tickets becomes - 1
				// When tickets = 3, t1 wakes up first, outputs - 1, and tickets changes to - 2
				// When tickets = 4, t1 wakes up first, outputs - 2, and tickets changes to - 3

				// The same data situation: when the thread tickets has not been output, another thread comes to work
				System.out.println(Thread.currentThread().getName() + "Ticket number:" + tickets--);
			} else {
				break;
			}
		}
	}
}

After running, there are several problems:
1. Generate oversold, - 1, - 2.
2. The same ticket is sold to many people.
3. How does multithreading security arise? A common situation is due to the randomness of threads + access latency.
4. How to judge whether the program has thread safety problems in the future? In a multithreaded program + shared data + multiple statement operations share data.

5, Synchrolock

Package the code that may have problems and let only one thread execute at a time. Synchronization is achieved through the sychronized keyword.
When multiple objects operate on shared data, synchronization lock can be used to solve the thread safety problem.

synchronized
 Synchronized (object){
    Code to be synchronized;
}

Characteristic

1. Premise 1: synchronization requires two or more threads.
 
2. Premise 2: multiple threads must use the same lock.
 
3. The disadvantage of synchronization is that it will reduce the efficiency of program execution. In order to ensure thread safety, performance must be sacrificed.
 
4. Methods that can be decorated are called synchronization methods, and the lock object used is this.
 
5. Code blocks that can be decorated are called synchronization code blocks, and lock objects can be arbitrary.

Case study:

public class TestThread3 {

	public static void main(String[] args) {

		Ticket3 t = new Ticket3();

		Thread t1 = new Thread(t, "one");
		Thread t2 = new Thread(t, "two");
		Thread t3 = new Thread(t, "three");
		Thread t4 = new Thread(t, "four");

		t1.start(); // The run method is called, not from scratch from the Ticket3 class, but from the run method
		t2.start();
		t3.start();
		t4.start();

	}
}

class Ticket3 implements Runnable {
	int tickets = 100;
	Object obj = new Object();

	public void run() {
		while (true) {

			// synchronized synchronization keyword can ensure data security and avoid concurrency
			// new Object() is a lock object, which is equivalent to adding a lock to new Object(). The thread accesses it with a key, and waits for the one without the key.
			// Lock position: must be the starting position of multithreading concurrency
			// The lock object of new Object() is not the same object. Each thread will create its own lock object, which is invisible between threads
			// synchronized (new Object()) {
			synchronized (obj) { // Or change obj to this. It must be the same object
				if (tickets > 0) {

					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					System.out.println(Thread.currentThread().getName() + "Ticket number:" + tickets--);
				} else {
					break;
				}
			}
		}
	}
}

6, Other ways of thread creation

ExecutorService/Executors

api

        ExecutorService

        execute(Runnable Task object) Drop task to thread pool

        Executors Tool class to assist in creating thread pool

        newFixedThreadPool(5) Thread pool of up to 5 threads

        newCachedThreadPool() Enough threads,Make the task unnecessary to wait

        newSingleThreadExecutor() Thread pool with only one thread

Case study:

//Impersonate thread pool
//ExecutorService function: improve the read-write efficiency of multi-threaded operations. All threads in the thread pool are runnable, no new, no start,
//If necessary, it will be taken away. When it is used up, it will be automatically returned to the pool to ensure the use of the next thread and improve the availability of the thread.
public class TestThread4 {

	public static void main(String[] args) {

		// Start Thread.start()
		// 1. Create a thread pool -- all threads in the pool are runnable
		// 2. Create the fixed thread pool newFixedThreadPool through the Executors tool class created by the thread pool
		ExecutorService pool = Executors.newFixedThreadPool(3);

		// 3. Use thread pool to work execute(m)
		// m is of Runnable type. Why can thread4 be used? Because thread4 is the interface grandson of Runnable
		for (int i = 0; i < 10; i++) {
			// pool.execute(new Thread4(i));
			pool.execute(new MyRunnable(i));
		}

	}
}
//Create multithreaded class mode 1
class Thread4 extends Thread {

	int i;

	Thread4() {
	}

	Thread4(int i) {
		this.i = i;
	}

	public void run() {
		System.out.println(getName() + ":" + i);
	}
}
//Create multithreaded class mode 2 -- recommended!!
class MyRunnable implements Runnable {

	int i;

	MyRunnable() {

	}

	MyRunnable(int i) {
		this.i = i;
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		System.out.println(Thread.currentThread().getName() + ":" + i);
	}
}

Callable/Future

Case study:

public class TestThread5 {

	// Test Callable to implement multithreading
	public static void main(String[] args) throws InterruptedException, ExecutionException {

		// Create thread pool object
		ExecutorService pool = Executors.newSingleThreadExecutor(); //Create a thread pool with only one thread

		// How to execute call? -- educetorservice. Submit()
		Future future = pool.submit(new MyCallable());

		// Get the return value of call()
		Object o = future.get();
		System.out.println(o);
	}
}

class MyCallable implements Callable {
	@Override
	public Object call() throws Exception {
		// TODO Auto-generated method stub
		return new Random().nextInt(100);
	}
}

The difference between Callable and Runnable

Callable Runnable
The call() method is executed
Method has return value
Method with throw exceptions
The run() method is executed
Method has no return value
Published 12 original articles, won praise 9, visited 9266
Private letter follow

Posted by wpsd2006 on Sun, 19 Jan 2020 00:37:14 -0800