20 Processes and Threads

Keywords: Java

Process concept

  • A process is a running program, such as QQ, that starts a process and the operating system allocates memory for that process. When we use Thunder, a process is started, and the operating system will allocate new memory space for Thunder.
  • A process is either an execution of a program or a running program. Is a dynamic process: there is its own process of generation, existence and extinction.
public class z1_CpuNums {
    public static void main(String[] args) {
        Runtime runtime = Runtime.getRuntime();
        //Get the current number of computer cpu cores
        int cpuNums = runtime.availableProcessors();
        System.out.println("cpu Number of available=" + cpuNums );
    }
}

What is Thread

  • Threads are created by processes and are an entity of processes
  • A process can have multiple threads.

Other related concepts

  • Single-threaded: Only one thread is allowed at a time

  • Multithreaded: Multiple threads can be executed at the same time, such as: a QQ process, multiple chat windows can be opened at the same time, a thunderstorm process, and multiple files can be downloaded at the same time

  • Concurrent: At the same time, multiple tasks are executed alternately, creating the illusion of "seemingly simultaneous". Simply put, the multitask implemented by a single-core cpu is concurrent.

  • Parallel: At the same time, multiple tasks are executed simultaneously, multi-core cpu can achieve parallel

Two ways to create a thread

  • There are two ways to create threads in Java

    • Inherit Thread class, override run method
    • Implement the Runnable interface, override the run method
  • When a class inherits the Thread class, it can be used as a thread

  • We'll rewrite the run method and write our own business code

  • The Thread class implements the run method of the Runnable interface

Thread Basic Usage

Inherit Thread Class

Opens a thread that outputs meow every 1 second and ends it 40 times

public class z1_Thread01 {
    public static void main(String[] args) {
        Cat cat = new Cat();
        //Start the thread and finally execute the run method of cat
        cat.start(); //The main thread opens a child thread
        //When main opens a child thread, instead of waiting for the child thread to finish executing before executing code down, it executes the following code immediately after opening
        //mian thread and child thread execute alternately
        for (int i = 0; i < 100; i++) {
            System.out.println(i + " thread= " + Thread.currentThread().getName());
        }


    }
}

class Cat extends Thread{
    int times = 0 ;
    @Override
    public void run(){
        while( true ){
            System.out.println("cat" + (++times) + " thread= " + Thread.currentThread().getName());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            if( times >= 40 ){
                break;
            }

        }

    }

}

When the start() method calls the start0() method, the thread does not necessarily execute immediately, it just makes the thread runnable. The exact time to execute depends on the CPU, which is dispatched by the same CPU

Implement Runnable Interface

  • Java is single-inherited and in some cases a class may have inherited a parent class, so it is obviously impossible to create threads by inheriting the Thread class method
  • Threads can be created by implementing the Runnable interface

Write a program that can be changed every 1 second. Output "hi!" in console and exit automatically 10 times after output. Please use the way to implement the Runnable interface

public class z2_Thread02 {
    public static void main(String[] args) {
        Dog dog = new Dog();
        //dog.statr() is wrong because there is no start method for the Runable interface
        //Create a Thread object, put a dog object (implementing Runnable) into Thread
        Thread thread = new Thread(dog);
        thread.start();
    }
}

class Dog implements Runnable{

    int count = 0 ;

    @Override
    public void run() {
        while( true ){
            System.out.println("Wangwang" + (++count) + " " +Thread.currentThread().getName() );
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if( count == 10 ){
                break ;
            }
        }

    }
}

Inherit Threadvs to implement Runnable

  • From a Java design point of view, creating threads by inheriting Thread or implementing the Runnable interface is essentially the same. You can see from the jdk document that the Thread class itself implements the Runnable interface
  • Implementing the Runnable interface is more appropriate when multiple threads share a single resource and avoids the limitation of single inheritance.

Ticketing system, into a simulation of three ticketing windows ticket 100.

public class z3_Multithreaded Ticketing {
    public static void main(String[] args) {
        SaleTicks saleTicks = new SaleTicks();
        Thread thread = new Thread(saleTicks);
        Thread thread1 = new Thread(saleTicks);
        Thread thread2 = new Thread(saleTicks);
        thread.start();
        thread1.start();
        thread2.start();
    }
}

class SaleTicks implements Runnable{

    private static int count = 100 ;
    @Override
    public void run() {
        while( true ){

            if( count <= 0 ){
                break;
            }

            System.out.println(Thread.currentThread().getName() + "One ticket, left" + (--count));
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

This code does not synchronize threads and may cause oversold.

Thread termination

  • When the thread finishes its task, it exits automatically
  • You can also stop threads by using variables to control how the run method exits, that is, by notification.

Thread Common Methods

  • setName sets the thread name.
  • getName returns the name of the thread
  • Start causes the thread to start execution; Java Virtual Machine underlying calls the thread's start0 method
  • Run calls the thread object run method
  • setPriority Change Thread Priority
  • getPriority gets the priority of the thread
  • sleep sleeps (suspends execution) the currently executing thread for a specified number of milliseconds
  • Interrupt interrupt interrupt thread
  • The gift of the yield thread. Leave the cpu for other threads to execute, but the timing of the concession is uncertain, so it may not necessarily succeed
  • Queuing of join threads. Once a queued thread succeeds, it must complete all tasks of the inserted thread first

Attention to detail

  • The bottom level of start creates new threads, calling run, run is a simple method call, and does not start new threads

  • Range of thread priority

  • Interrupt, interrupts the thread, but does not really end it. So it's generally used to interrupt a sleeping thread

  • Sleep: The static method of a thread to sleep the current thread

User and daemon threads

  • User threads: Also called worker threads, when a thread's task finishes executing or is notified to end
  • Daemon threads: Typically served for the worksite, when all user threads end, the daemon thread automatically ends
  • Common daemon threads: garbage collection mechanisms
public class z4_Daemon Threads {
    public static void main(String[] args) {
        T1 t1 = new T1();
        Thread thread = new Thread(t1);
        //Set this thread as a daemon thread - >main thread exits, daemon thread exits
        thread.setDaemon(true);
        thread.start();
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName() + ".............");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

class T1 implements Runnable{

    @Override
    public void run() {
        while( true ){
            System.out.println("Daemon Threads.....");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

Thread.State enumeration in JDK represents the centralized state of threads

Thread synchronization mechanism

  • In multi-threaded programming, some sensitive data is not allowed to be accessed by multiple threads at the same time. Synchronized access technology is used to ensure data is accessed by at most one thread at any time to ensure data integrity.
  • It can also be understood that threads synchronize, that is, when one thread is operating on memory, no other thread can operate on the memory address until the other thread finishes the operation.

Synchronization method - sysnchronized

  • Synchronize Code Blocks
   sysnchronized(object){  //Obtain object lock to operate on synchronization code
      //Code that needs to be synchronized
   }
  • sysnchronized can also be placed in a method declaration to indicate that the entire method is a synchronous method
  public sysnchronized void m(String name){

   }

Solve ticket oversold problem with sysnchronized

public class z5_Use synchronization mechanism to sell tickets {
    public static void main(String[] args) {
        SaleTicks2 saleTicks = new SaleTicks2();
        Thread thread = new Thread(saleTicks);
        Thread thread1 = new Thread(saleTicks);
        Thread thread2 = new Thread(saleTicks);
        thread.start();
        thread1.start();
        thread2.start();
    }
}

class SaleTicks2 implements Runnable{

    private static int count = 100 ;

    public synchronized void sell(){
        while( count > 0 ){

            System.out.println(Thread.currentThread().getName() + "One ticket, left" + (--count));
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void run() {
        sell();
    }
}


mutex

  • In Java, the concept of object mutex is introduced to ensure the integrity of shared data operations.
  • Each object corresponds to a tag called a mutex that guarantees that only one live access to the object can be made at any time
  • The keyword sysnchronized is used to associate mutually exclusive locks with objects. When an object is decorated with sysnchronized, it means that the object can only be accessed by one thread at any time
  • Limitations of synchronization: Causes inefficient program execution
  • Synchronization method (non-static) locks can be this or other objects (requiring the same object)
  • Synchronization method (static) locks are the current class itself

Mutex Attention to Details

  • Synchronization method if static is not used: the default lock object is this

  • If the method is decorated with static, the default lock object is the current class.class

  • Steps to achieve

    • Locked code needs to be analyzed first
    • Choose Synchronization Code Fast or Synchronization Method
    • Require multiple threads to have the same object

Thread Deadlock

Multiple threads occupy the object's lock resources, but they do not want to, resulting in deadlocks, which must be avoided in programming.

The following actions will not release the lock

  • When a thread executes a synchronization code block or synchronization method, the program calls the Thread.sleep(), Thread.yield() methods to suspend the execution of the current thread without releasing the lock

  • When a thread executes a synchronous code block, the suspend() method of the thread is called by another thread, and the thread does not release the lock.

Practice

Start two threads in the main method, and the first thread loops through random printing of integers up to 100 until the second thread reads the Q command from the keyboard

public class z6_homework1 {
    public static void main(String[] args) {
        A a = new A();
        B b = new B(a);
        Thread thread = new Thread(a);
        Thread thread1 = new Thread(b);
        thread.start();
        thread1.start();
    }
}

class A implements Runnable{

    private boolean loop = true ;

    @Override
    public void run() {
        while( loop ){
            System.out.println((int)(Math.random()*100 + 1));
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public boolean isLoop() {
        return loop;
    }

    public void setLoop(boolean loop) {
        this.loop = loop;
    }
}


class B implements Runnable{

    private A a ;

    public B(A a) {
        this.a = a;
    }

    private Scanner in = new Scanner(System.in) ;

    @Override
    public void run() {
        while( true ){
            String s = in.nextLine();
            if( "Q".equalsIgnoreCase(s) ){
                a.setLoop(false);
                break;
            }
        }

    }
}

Posted by noise on Sun, 28 Nov 2021 12:46:43 -0800