Processes and threads

process

Processes are the smallest unit of resource allocation in the operating system. By default, an App is a single process. You can also start multiple processes for an App, which are independent of each other.

thread

Threads are the smallest unit of CPU scheduling in which tasks are executed. Threads are attached to a process, and when there are no threads in a process that can perform tasks, the thread is reclaimed. A process can have multiple threads.

CPU time slice rotation mechanism

When we take the subway, we may listen to the song while reading the article. We will think that the article APP and the song APP are running at the same time. In fact, they are not running at the same time, the system provides a KIND of CPU time slice rotation mechanism, the process is allocated to the time slice it starts to work, but the time slice is very short, the CPU switch quickly and frequently, this creates the illusion of running at the same time.

Baidu encyclopedia explains:

Time slice scheduling is one of the oldest, simplest, fairest and most widely used algorithms. Each process is assigned a period of time, called its slice, which is the amount of time the process is allowed to run. If the process is still running at the end of the time slice, the CPU is stripped and allocated to another process. If the process blocks or ends before the time slice ends, the CPU switches immediately. All the scheduler has to do is maintain a list of ready processes that are moved to the end of the queue when the process runs out of its time slice.

The only interesting thing about slice rotation scheduling is the length of the slice. Switching from one process to another takes time — saving and loading register values and memory images, updating various tables and queues, and so on. If a process switch, sometimes called a context switch, takes 5 milliseconds, and if the time slice is set to 20 milliseconds, the CPU will take 5 milliseconds to switch after doing 20 milliseconds of useful work. Twenty percent of CPU time is wasted in administrative overhead.

To improve CPU efficiency, we can set the time slice to 500 milliseconds. Only 1% of the time is wasted. But consider what happens in a time-sharing system when ten interactive users press enter almost simultaneously? Assuming all the other processes use their full time slice, the last unfortunate process will have to wait five seconds for a chance to run. Most users can’t stand the 5 seconds it takes to respond to a short command. The same problem can occur on a personal computer that supports multiple programs.

The conclusions can be summarized as follows: setting the time slice too short will lead to too many process switches and reduce CPU efficiency; Too long may cause poor response to short interaction requests. A time slice of 100 milliseconds is usually a reasonable compromise.

Parallelism and concurrency

Parallelism is simultaneous and concurrency is alternate. For example: concurrency is a person I hit three people, to finish one and then the next, take turns to hit (CPU rotation mechanism); Parallelism is three people hitting three people at the same time.

Several ways to create threads

Three (technically only two).

1, inherit Thread:

public class SubThread {
    @Override
    public void run(a) {
        super.run(); }}public static void main(String[] args) {
    SubThread thread = new SubThread();
	thread.start();
}
Copy the code

2, implement Runnable:

public class MyRunnable implements Runnable {
    @Override
    public void run(a) {}}public static void main(String[] args) {
    MyRunnable runnable = new MyRunnable();
    Thread thread = new Thread(runnable);
    thread.start();
}
Copy the code

Callable<T> :

public class MyCallable implements Callable<String> {
    @Override
    public String call(a) throws Exception {
        return "result"; }}public static void main(String[] args) {
    MyCallable callable = new MyCallable();
    FutureTask<String> task = new FutureTask<>(callable);
    Thread thread = new Thread(task);
    thread.start();
}
Copy the code

Why are there technically only two?

There are comments in the Thread source that there are two ways to create a new Thread.

 * There are two ways to create a new thread of execution. One is to
 * declare a class to be a subclass of <code>Thread</code>. This
 * subclass should override the <code>run</code> method of class
 * <code>Thread</code>. An instance of the subclass can then be
 * allocated and started. 


 * The other way to create a thread is to declare a class that
 * implements the <code>Runnable</code> interface. That class then
 * implements the <code>run</code> method. An instance of the class can
 * then be allocated, passed as an argument when creating
 * <code>Thread</code>, and started.
Copy the code

FutureTask implements the RunnableFuture interface, and the RunnableFuture interface inherits from the Runnable interface, so FutureTask is also a Runnable. It is essentially no different from the second Runnable method.

So what’s the difference between these three approaches?

Java is a single inheritance with multiple implementations, so the first approach has poor scalability. The second approach can also implement other interfaces, but they have no return value in common. The third method has a return value whose return value type is the generic type in the declared class.

The difference between threads run and start

The run method is where the task is performed. It is just a normal method that can be called multiple times. Calling the run method alone does not start a thread. The start method will actually start the thread. The start method will call the native underlying method, and then call the run method to execute the task. The start method can only be executed once, and multiple executions throw an exception.

How can threads be stopped safely

1. The thread stops automatically after the task in the run method is executed

2. Stop manual interference. In older versions of the JDK, the stop method was used to stop a thread, but it is now deprecated because it is too violent to stop a task regardless of its status and does not ensure that resources are released properly. A thread should be marked for interruption with interrupt() (remember that it is marked only and does not interrupt the thread immediately), and the thread checks for interruption through isInterrupted(), You can also use Thread’s static method thread.interrupted () to determine whether the current Thread has been interrupted, but this changes the interrupt flag to false.

The way threads are serial

Call thread’s join() method to add threads to the current thread, serializing several threads.

class Thread1 extends Thread {
    @Override
    public void run(a) {
        super.run();
        System.out.println("Thread1"); }}class Thread2 extends Thread {
    @Override
    public void run(a) {
        super.run();
        System.out.println("Thread2"); }}public static void main(String[] args) throws InterruptedException {
    Thread1 thread1 = new Thread1();
    thread1.start();
    thread1.join(); // Note that start must be followed by join

    Thread2 thread2 = new Thread2();
    thread2.start();
    thread2.join();

    System.out.println("Main Thread");
}

/ / print
Thread1
Thread2
Main Thread
Copy the code

The above code will not execute thread2 until thread1 completes, and will continue to execute the main thread code after thread2 completes.