Multithreading: thread creation and thread safety

Keywords: less JDK jvm

Article directory

Program, process, thread

Program: a set of instructions written in a certain language to complete a specific task. That is, a static code, a static object.
Process: an execution process generated by a program, or a running program. Is a dynamic process: by itself
	  The process of emergence, existence and extinction - life cycle.
	  >For example: QQ in operation, MP3 player in operation
	  >Program is static, process is dynamic
	  >As the unit of resource allocation, the system will match different memory areas for each process at runtime
 Thread: a process can be further refined into a thread, which is an execution path within a program.
	  >If a process executes multiple threads simultaneously, it supports multiple threads
	  >As the smallest unit of process scheduling and execution, each thread has its own running stack and program counter (pc). The cost of thread switching is small
	  >Multiple threads in a process share the same memory unit / memory address space - > they allocate objects from the same heap. They can access the same
	   Variables and objects. This makes the communication between threads more convenient and efficient. However, system resources shared by multiple threads may bring security risks.

Create thread

 1. How to create threads
    -1: Inherit Thread class (Thread class implements Runnable interface)
    -2: Implement the Runnable interface (recommended). Class implements the interface, and can inherit other classes. Interfaces are implemented in multiple ways. Inheritance is single inheritance.)
    ----------------------------------------
    Inherit Thread class:
    public class ThreadA extends Thread{
    	//Override run method
		@Override
		public void run(){
		}
	}
	To implement the Runnable interface:
	public class ThreadA implements Runnable{
    	//Override run method
		@Override
		public void run(){
		}
	}

Startup thread

1. Call the start() method of the thread. Note: calling the start() method is the real starting thread, while calling the run() method is equivalent to
   A normal method was called and the thread could not be started.
   -------------------------------------------------------
   Inherited Thread start Thread mode:
   ThreadA t = new ThreadA();
   t.start();
   
   To implement the start thread mode of the Runnable interface:
   /**
   *Methods in Thread class      
   *  ThreadA t1= new Thread(Runnable target)
   */
   ThreadA t = new Thread(new ThreadA());
	t.start();

Thread safety

  • Reasons for thread safety

     1. The uncertainty of multi thread execution causes the instability of execution results
     2. For example, the sharing of ledgers by multiple threads will cause incomplete operations and damage data
    

    As shown in the figure below, the original balance of the account is 3000 yuan. A and B withdraw 2000 yuan from the account at the same time (concurrently), and the account balance becomes - 1000 yuan. This problem is thread safety.

  • Solving thread safety problem -- thread synchronization

     Mode 1: synchronize code blocks
     1. Synchronous monitor, commonly known as lock. Any object of a class can act as a lock, requiring multiple threads to share the same lock
     2. The synchronization monitor can be: current class. Class (Class clazz = current class. class(), class is loaded only once,
     					So the object created in this way is unique), other class objects, this (object of current class)
     3. In the way of inheriting Thread class to create multithreading, be careful to use this (current object) as synchronization monitor (ensure)
     4. In the way of implementing Runnable interface to create multithreading, we can consider using this as synchronization monitor
     Synchronized (synchronization monitor){
     	//Code to be synchronized (code to operate shared data, such as the number of train tickets). The synchronized code cannot contain less or more
     }		
     
     Mode 2: synchronization method
     Advantages: solve the problem of thread safety
     Disadvantage: when synchronizing code. Only one thread can participate, and other threads wait. It is a single thread process with low efficiency
     1. If the code that operates on shared data is fully declared in a method, we might as well declare this method as a synchronous method
     2. Summary:
     		(1) The synchronization method still involves the synchronization monitor, but we do not need to display the declaration
     		(2) Non static synchronization method, the synchronization monitor is this;
     			 Static synchronization method, synchronization monitor is: the current class itself (class. class).
    

To solve the problem of thread safety (to realize Runnable) -- synchronous code block

public class ThreadA implements Runnable{

	    private int ticket = 100;
	    /**
	     * Correct way
	     */
	    //Object obj = new Object();
	
	    @Override
	    public void run() {
	        //Wrong way to create multiple Object objects
	        //Object obj = new Object();
	        while (true){
	            //Wrong way to create multiple Object objects
	            //synchronized(new Object()) {
	            //synchronized(ThreadA .class) {
	            synchronized(this) { 
	            //Share a lock
	            //synchronized(obj) {
	                if (ticket > 0) {
	                    try {
	                        Thread.sleep(100);
	                    } catch (InterruptedException e) {
	                        e.printStackTrace();
	                    }
	                    System.out.println(Thread.currentThread().getName() + ":Buy a ticket with the ticket number" + ticket);
	                    ticket--;
	                } else {
	                    break;
	                }
	            }
	        }
	    }
	
	    public static void main(String[] args) {
	        ThreadA t = new ThreadA();
	
	        Thread t1 = new Thread(t);
	        Thread t2 = new Thread(t);
	        Thread t3 = new Thread(t);
	
	        t1.setName("Window 1");
	        t2.setName("Window 2");
	        t3.setName("Window 3");
	
	        t1.start();
	        t2.start();
	        t3.start();
	    }
	}

To solve the problem of thread safety (to realize Runnable) -- synchronization method

The synchronization monitor of the synchronization method is this

public class ThreadC implements Runnable{

    private int ticket = 100;

    @Override
    public void run() {
        while (true){
            sellTicket();
        }
    }
    
	//Synchronization method, decorated with the keyword synchronized
    private synchronized void sellTicket(){
        if(ticket > 0){
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + ",Ticket number:" + ticket);
            ticket--;
        }
    }

    public static void main(String[] args) {
        ThreadC t = new ThreadC();

        Thread t1 = new Thread(t);
        Thread t2 = new Thread(t);
        Thread t3 = new Thread(t);

        t1.setName("Window 1");
        t2.setName("Window 2");
        t3.setName("Window 3");

        t1.start();
        t2.start();
        t3.start();
    }
}

To solve the Thread safety problem (inherit Thread) - synchronous code block

public class ThreadB extends Thread{

    private int ticket = 100;

    //Correct way
    //private Object obj = new Object();


    @Override
    public void run() {
        while (true){
            synchronized (ThreadB.class){  //Correct way
//            synchronized (obje) {/ / correct way
//            synchronized (this) {/ / there will be errors in this mode
                if(ticket > 0){
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+",Ticket number:"+ticket);
                    ticket--;
                }else{
                    break;
                }
            }
        }
    }

    public static void main(String[] args) {
        ThreadB t = new ThreadB();

        Thread t1 = new Thread(t);
        Thread t2 = new Thread(t);
        Thread t3 = new Thread(t);

        t1.setName("Window 1");
        t2.setName("Window 2");
        t3.setName("Window 3");

        t1.start();
        t2.start();
        t3.start();
    }
}

To solve the Thread safety problem (inherit Thread) - synchronization method

public class ThreadD extends Thread{

    private int ticket = 100;

    @Override
    public void run() {
        while (true){
            sellTicket();
        }
    }

    //private synchronized void sellTicket() {/ / error resolution
    private static synchronized void sellTicket(){ // Monitor is thread.class
        if(ticket > 0){
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + ",Ticket number:" + ticket);
            ticket--;
        }
    }

    public static void main(String[] args) {
        ThreadD t = new ThreadD();

        Thread t1 = new Thread(t);
        Thread t2 = new Thread(t);
        Thread t3 = new Thread(t);

        t1.setName("Window 1");
        t2.setName("Window 2");
        t3.setName("Window 3");

        t1.start();
        t2.start();
        t3.start();
    }
}

The third way to solve the thread safety problem: Lock lock - New in JDK5.0

class Window implements Runnable{
    private int ticket = 100;

    /**
     * Instantiation lock
     * Parameter fair(boolean):
     *      true-Fair competition lock
     *      false(Default) - random contention lock
     *  When multithreading is implemented by inheritance, since multiple objects are created, lock needs to be set to static to class level to ensure the uniqueness of locks
     */
    private ReentrantLock lock = new ReentrantLock();

    @Override
    public void run() {
        while (true){
            try {
                //Locking ensures that the following code is single threaded
                lock.lock();

                if(ticket > 0){
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+",Ticket number:"+ticket);
                    ticket--;
                }else {
                    break;
                }
            } finally {
                //Unlock
                lock.unlock();
            }
        }
    }
}


public class LockTest {

    public static void main(String[] args) {
        Window w = new Window();

        Thread t1 = new Thread(w);
        Thread t2 = new Thread(w);
        Thread t3 = new Thread(w);

        t1.setName("Window 1");
        t2.setName("Window 1");
        t3.setName("Window 1");

        t1.start();
        t2.start();
        t3.start();
    }
}

Similarities and differences between Synchronized and Lock

The same:
Both of them can solve the problem of thread safety

Different:
	1. Synchronized will automatically release the lock (synchronization monitor) after executing the corresponding synchronization code.
	2. Lock requires us to add locks manually, call lock() method, and release locks manually, call unlock() method.
	3. With Lock lock, the JVM will spend less time to schedule threads, and the performance is better. And it has better extensibility (providing more subclasses).
	
Two methods are preferred:
Lock → synchronize code block (has entered method body and allocated corresponding resources) → synchronize method (outside method body)
Published 1 original article, praised 0, visited 59
Private letter follow

Posted by surreal5335 on Wed, 26 Feb 2020 20:25:07 -0800