Multithreading Principle Anonymous Internal Class Implements Thread Creation Thread Security Thread Synchronization Thread State

Keywords: Java

Multithreading principle

Multithreaded Memory Diagram

There are two ways to get a thread name:

Get the name of the thread:
1. Use the method getName() in the Thread class
String getName() returns the name of the thread.
2. You can get the currently executing thread first and use the getName() method in the thread to get the name of the thread
Static Thread current Thread() returns a reference to the currently executing thread object.

Example:

// Define a subclass of the Thread class

public class MyThread extends Thread {
    //Override the run method in the Thread class to set the thread task

    @Override
    public void run() {
        //Get Thread Name
       /* String name = getName();
        System.out.println(name);*/

       /* Thread t = Thread.currentThread();
        System.out.println(t);//Thread[Thread-0,5,main]
        String name = t.getName();
        System.out.println(name);*/

        //Chain programming
        System.out.println(Thread.currentThread().getName());
    }
}
/*
*   Thread name:
        Main thread:main
        New threads: Thread-0, Thread-1, Thread-2

                */
public class Demo01GetThreadName {

    public static void main(String[] args) {
        //Create subclass object of Thread class
        MyThread mt = new MyThread();
        //Call the start method, open a new thread, execute the run method
        mt.start();

        new MyThread().start();

        System.out.println(Thread.currentThread().getName());//main
    }
}

Two ways to set a thread name
Set the name of the thread: (Understand)
1. Use the method setName (name) in the Thread class
void setName(String name) changes the thread name to be the same as the parameter name.
2. Create a construction method with parameters that pass the name of the thread;Call the parameterized constructor of the parent class, pass the thread name to the parent, and have the parent (Thread) give the child a name
Thread(String name) assigns a new Thread object.

public class MyThread extends Thread {

    public MyThread(){

    }
    public MyThread(String name){
        super(name);

    }
    @Override
    public void run() {
        //Get the name of the thread
        System.out.println(Thread.currentThread().getName());

    }
}
public class Demo01SetThreadName {
    public static void main(String[] args) {
        //Open multithreading
        MyThread mt = new MyThread();
        mt.setName("w");
        mt.start();//w

        //Open multithreading
        new MyThread("z").start();//z
    }


}

Sleep method in Thread

/*
    public static void sleep(long millis):Suspends (temporarily suspends) the currently executing thread for a specified number of milliseconds.
    Static method, which can be called directly
    After milliseconds have ended, the thread continues execution
 */
public class Demo01Sleep {
    public static void main(String[] args) {
        //Analog stopwatch
        for (int i = 1; i <=60 ; i++) {
            System.out.println(i);

            //Sleep the program for one second using the Sleep method of the Thread class 
            try {
                Thread.sleep(Long.parseLong("1000"));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    }
}

Second way to create threads

The second way to create a multithreaded program is to implement the Runnable interface
java.lang.Runnable
Runnable interfaces should be implemented by classes that intend to execute their instances through a thread. Classes must define a parameterless method called run.
Construction method of java.lang.Thread class
Thread(Runnable target) assigns a new Thread object.
Thread(Runnable target, String name) assigns a new Thread object.

Steps to achieve:
1. Create an implementation class for the Runnable interface
2. Override the run method of the Runnable interface in the implementation class to set the thread task
3. Create an implementation class object for the Runnable interface
4. Create Thread class object, pass Runnable interface implementation class object in construction method
5. Call the start method in the Thread class to open a new thread to execute the run method

Example:

public class Demo01Runnable {
    public static void main(String[] args) {
        //3. Create an implementation class object for the Runnable interface
        Runnable run = new RunnableImpl();
        // 4. Create Thread class object, pass Runnable interface implementation class object in construction method
        Thread t = new Thread(run);
        /// 5. Call the start method in the Thread class to open a new thread to execute the run method
        t.start();


        for (int i = 0; i < 30; i++) {
            System.out.println(Thread.currentThread().getName()+ i);
        }
    }
}
//1. Create an implementation class for the Runnable interface
public class RunnableImpl implements Runnable  {
    //2. Override the run method of the Runnable interface in the implementation class to set the thread task
    @Override
    public void run() {
        for (int i = 0; i < 30; i++) {
            System.out.println(Thread.currentThread().getName()+ i);
        }

    }
}

Benefits of implementing the Runnable interface to create multithreaded programs:
1. Avoid the limitation of single inheritance
A class can only inherit one class (a person can only have one parent). A class that inherits the Thread class cannot inherit other classes
Implements the Runnable interface, inherits other classes, and implements other interfaces
2. Enhance the extensibility of the program and reduce the program coupling (decoupling)
Implement the Runnable interface by separating (decoupling) the set thread task from the start of a new thread
In the implementation class, the run method is overridden: used to set thread tasks
Create a Thread class object and call the start method: to open a new thread

Anonymous internal class implements thread creation
Anonymous Internal Class Approach for Thread Creation

Anonymous: No name
Internal Classes: Classes written inside other classes

Anonymous Internal Class Role: Simplify Code
One step at a time is to inherit a subclass from its parent, override its methods, and create subclass objects
Implement classes to implement class interfaces, override methods in interfaces, and create class object composites in one step
End product of anonymous internal class: subclass/implementation class object, which has no name

Format:
new parent/interface (){
Duplicate methods in parent/interface
};

public class Demo01InnerClassThread {
    public static void main(String[] args) {
        //Thread is the parent of a thread
        new Thread(){
            //Override run method, set thread task

            @Override
            public void run() {
                for (int i = 0; i < 20; i++) {
                    System.out.println(Thread.currentThread().getName()+ "-->" + "Dark horse");
                }
            }
        }.start();

        //Thread's interface Runnable
        //Runnable r = new RunnableImpl(); polymorphism
        Runnable r = new Runnable(){
            @Override
            public void run() {
                for (int i = 0; i < 20; i++) {
                    System.out.println(Thread.currentThread().getName() + "-->" + "W");
                }
            }
        };
        new Thread(r).start();

        //Ways to simplify interfaces
        new Thread(new Runnable(){
            @Override
            public void run() {
                for (int i = 0; i < 20; i++) {
                    System.out.println(Thread.currentThread().getName() + "-->" + "z");
                }
            }
        }).start();
    }
}

Thread Security
Security issues with multithreaded use of shared data

Example:

/*
*       Simulate ticket sales
*       Create three threads and open them at the same time to sell shared tickets*/
public class Demo01Ticket {
    public static void main(String[] args) {
        //Create implementation class object for Runnable interface
        RunnableImpl run = new RunnableImpl();
        //Create Thread class object, pass Runnable interface in construction method to implement class object
        Thread t0 = new Thread(run);
        Thread t1 = new Thread(run);
        Thread t2 = new Thread(run);
        //Call the start method to open multithreading
        t0.start();
        t1.start();
        t2.start();

    }
}
/* Achieving ticket sales cases*/
public class RunnableImpl implements Runnable {
    //Define a multi-threaded shared ticket source
    private int ticket = 100;

    //Set Thread Task: Buy Ticket
    @Override
    public void run() {
        //Use Dead Loop to Repeat Ticket Selling
        while (true){
            //
            //Determine whether a vote exists
            if (ticket>0){
                System.out.println(Thread.currentThread().getName() + "Selling" + ticket + "Tickets");
                ticket--;
            }
        }

    }
}

Generation principle
Thread Synchronization
The first way to solve thread security problems
Synchronize code blocks:
Thread security issue in ticket selling case

  • Nonexistent and duplicate tickets sold
  • The first solution to thread security issues is to use synchronous code blocks
  • Format:
  • Synchronized (lock object){
  • Code that may have security issues (code that accesses shared data)
  • }
  • Be careful:
    1. Any object can be used by locking objects in the code block
    2. However, you must ensure that multiple threads are using the same lock object
    3. Lock the object:
    Lock the synchronization block and let only one thread execute in it

Example:

public class RunnableImpl implements Runnable {
    //Define a multi-threaded shared ticket source
    private int ticket = 100;
    //Create a lock object
    Object obj = new Object();

    //Set Thread Task: Buy Ticket
    @Override
    public void run() {
        //Use Dead Loop to Repeat Ticket Selling
        while (true){
            //Synchronize Code Blocks
            synchronized (obj){
                {
                    //Determine whether a vote exists
                    if (ticket>0){
                        try {
                            Thread.sleep(10);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println(Thread.currentThread().getName() + "Selling" + ticket + "Tickets");
                        ticket--;
                    }
                }
            }
        }

    }
}
/*
*       Simulate ticket sales
*       Create three threads and open them at the same time to sell shared tickets*/
public class Demo01Ticket {
    public static void main(String[] args) {
        //Create implementation class object for Runnable interface
        RunnableImpl run = new RunnableImpl();
        //Create Thread class object, pass Runnable interface in construction method to implement class object
        Thread t0 = new Thread(run);
        Thread t1 = new Thread(run);
        Thread t2 = new Thread(run);
        //Call the start method to open multithreading
        t0.start();
        t1.start();
        t2.start();

    }
}

Principle:

The second way to solve thread security issues: the synchronization method

Thread security issue in ticket selling case

  • Nonexistent and duplicate tickets sold

  • Second solution to thread security issues: using synchronization

  • Steps to use:
    1. Put code that accesses shared data into a method
    2. Add synchronized modifiers to methods

    Format: Format that defines the method
    Modifier synchronized return value type method name (parameter list) {
    Code that may have thread security issues (code that accesses shared data)

Example:

public class RunnableImpl implements Runnable {
    //Define a multi-threaded shared ticket source
    private int ticket = 100;


    //Set Thread Task: Buy Ticket
    @Override
    public void run() {
        //Use Dead Loop to Repeat Ticket Selling
        while (true) {

            payTicket();

        }
    }
            /* Define a Synchronization Class Method
            *  Synchronization methods also lock code inside the method
            *  Let only one thread execute
            *  Who is the lock object for the synchronization method?
            *  Is to implement the class object new RunnableImpl()
            *  That is this*/
            public synchronized void payTicket(){
            Can also be used synchronized(this){}
            //Determine whether a vote exists
                if (ticket>0){
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "Selling" + ticket + "Tickets");
                    ticket--;
                }
            }
            }
/*
*       Simulate ticket sales
*       Create three threads and open them at the same time to sell shared tickets*/
public class Demo01Ticket {
    public static void main(String[] args) {
        //Create implementation class object for Runnable interface
        RunnableImpl run = new RunnableImpl();
        //Create Thread class object, pass Runnable interface in construction method to implement class object
        Thread t0 = new Thread(run);
        Thread t1 = new Thread(run);
        Thread t2 = new Thread(run);
        //Call the start method to open multithreading
        t0.start();
        t1.start();
        t2.start();

    }
}

Static synchronization method

public class RunnableImpl implements Runnable {
    //Define a multi-threaded shared ticket source
    private static int ticket = 100;


    //Set Thread Task: Buy Ticket
    @Override
    public void run() {
        //Use Dead Loop to Repeat Ticket Selling
        while (true) {

            payTicket();

        }
    }
    /*
        Static synchronization method
        Who is the lock object?
        Can't be this
        this Is generated after the object is created, static methods take precedence over objects
        The lock object of the static method is the class property of the class-->class file object (reflection)
*/
            public static synchronized void payTicket(){
            //Determine whether a vote exists
            Can also be used synchronized(RunnableImpl.class){}
                if (ticket>0){
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "Selling" + ticket + "Tickets");
                    ticket--;
                }
            }
            }

A third way to solve thread security issues: Lock locks

/* Thread security issue in ticket selling case
*  Nonexistent and duplicate tickets sold
*
* A third solution to thread security issues: using Lock locks
*    java.util.concurrent.locks.Lock Interface
    Lock The implementation provides a wider range of locking operations than can be obtained using synchronized methods and statements.
    Lock Methods in interfaces:
        void lock()Acquire locks.
        void unlock()  Release the lock.
    java.util.concurrent.locks.ReentrantLock implements Lock Interface


    Steps to use:
        1.Create a ReentrantLock object at the member location
        2.Call the method lock in the Lock interface to acquire a lock before code that might have security problems
        3.Call the method unlock in the Lock interface to release the lock after code that might have security problems
    }*/
public class RunnableImpl implements Runnable {
    //Define a multi-threaded shared ticket source
    private static int ticket = 100;
//     1. Create a ReentrantLock object in the member location

    Lock l = new ReentrantLock();


    //Set Thread Task: Buy Ticket
    @Override
    public void run() {
        //Use Dead Loop to Repeat Ticket Selling
        while (true) {
//      2. Call the method lock in the Lock interface to acquire a lock before code that might have security problems
            l.lock();
        //Determine whether a vote exists
            if (ticket>0){
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "Selling" + ticket + "Tickets");
                ticket--;
            }
//      3. Call the method unlock in the Lock interface to release the lock after code that may have security problems
            l.unlock();
        }

        }
    }
/*
*       Simulate ticket sales
*       Create three threads and open them at the same time to sell shared tickets*/
public class Demo01Ticket {
    public static void main(String[] args) {
        //Create implementation class object for Runnable interface
        RunnableImpl run = new RunnableImpl();
        //Create Thread class object, pass Runnable interface in construction method to implement class object
        Thread t0 = new Thread(run);
        Thread t1 = new Thread(run);
        Thread t2 = new Thread(run);
        //Call the start method to open multithreading
        t0.start();
        t1.start();
        t2.start();

    }
}

Another way of writing:

public class RunnableImpl implements Runnable {
    //Define a multi-threaded shared ticket source
    private static int ticket = 100;
//     1. Create a ReentrantLock object in the member location

    Lock l = new ReentrantLock();


    //Set Thread Task: Buy Ticket
    @Override
    public void run() {
        //Use Dead Loop to Repeat Ticket Selling
        while (true) {
//      2. Call the method lock in the Lock interface to acquire a lock before code that might have security problems
            l.lock();
        //Determine whether a vote exists
            if (ticket>0){
                try {
                    Thread.sleep(10);
                    System.out.println(Thread.currentThread().getName() + "Selling" + ticket + "Tickets");
                    ticket--;
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
//      3. Call the method unlock in the Lock interface to release the lock after code that may have security problems
                    l.unlock();//The lock can be released regardless of whether the program is abnormal or not
                }

            }

        }

        }
    }

Six state threads

1 Timing wait state
2 Lock blocking state
3 Wireless Wait State

Case Study:

/*
    Waiting to wake up case: communication between threads
        Create a customer thread (consumer): inform the boss of the type and number of buns you want, call the wait method, discard the execution of the cpu, and enter the WAITING state (unlimited waiting)
        Create a boss thread (producer): after 5 seconds of cooking, call the notify method to wake up the customer to eat the bun

    Be careful:
        Customer and owner threads must be wrapped in synchronous blocks of code to ensure that only one execution can wait and wake up
        The lock object used synchronously must be guaranteed to be unique
        Only lock objects can call wait and notify methods

    Object Methods in Classes
    void wait()
          Causes the current thread to wait before other threads invoke the notify() or notifyAll() methods of this object.
    void notify()
          Wake up a single thread waiting on this object monitor.
          Will continue executing the code after the wait method
 */
public class Demo01 {
    public static void main(String[] args) {
        //Create a lock object
        Object obj = new Object();
        //Create a customer thread (consumer)
        new Thread(){
            @Override
            public void run() {
                //Ensure that only one execution is allowed for wait and wake-up
                synchronized (obj){
                    System.out.println("Tell your boss what kind and quantity of buns you want");
                    try {
                        obj.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                //Code executed after wakeup
                System.out.println("eat");
            }
        }.start();
    // Create a Boss Thread (Producer)
        new Thread(){
            @Override
            public void run() {
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (obj){
                    System.out.println("The owner informs the customer when he makes the bun in 5 seconds");
                    obj.notify();

                }
            }
        }.start();
    }
}

Two methods of waiting state

/*
    There are two ways to get into TimeWaiting
    1.Using the sleep(long m) method, the thread wakes up to the Runnable/Blocked state after the end of the millisecond value
    2.With the wait(long m) method, the wait method automatically wakes up if it has not been waked up by notify after the end of the millisecond value, and the thread wakes up to the Runnable/Blocked state

    Ways to wake up:
         void notify() Wake up a single thread waiting on this object monitor.
         void notifyAll() Wake up all threads waiting on this object monitor.
 */
public class Demo02 {
    public static void main(String[] args) {
        //Create lock objects to ensure uniqueness
        Object obj = new Object();
        // Create a customer thread (consumer)
        new Thread(){
            @Override
            public void run() {
                //Waiting to buy buns
                while(true){
                    //Ensuring that only one thread can be executed while waiting and waking up requires synchronization technology
                    synchronized (obj){
                        System.out.println("Customer 1 tells the boss what kind and quantity of buns he wants");
                        //Call the wait method, discard the execution of the cpu, and enter the WAITING state (wait indefinitely)
                        try {
                            obj.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        //Code executed after wakeup
                        System.out.println("The buns are ready,Customer 1 eats!");
                        System.out.println("---------------------------------------");
                    }
                }
            }
        }.start();

        // Create a customer thread (consumer)
        new Thread(){
            @Override
            public void run() {
                //Waiting to buy buns
                while(true){
                    //Ensuring that only one thread can be executed while waiting and waking up requires synchronization technology
                    synchronized (obj){
                        System.out.println("Customer 2 tells the boss what kind and quantity of buns he wants");
                        //Call the wait method, discard the execution of the cpu, and enter the WAITING state (wait indefinitely)
                        try {
                            obj.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        //Code executed after wakeup
                        System.out.println("The buns are ready,Customer 2 Serves!");
                        System.out.println("---------------------------------------");
                    }
                }
            }
        }.start();

        //Create a Boss Thread (Producer)
        new Thread(){
            @Override
            public void run() {
                //Keep making buns
                while (true){
                    //It took 5 seconds to make buns
                    try {
                        Thread.sleep(5000);//Make buns in 5 seconds
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    //Ensuring that only one thread can be executed while waiting and waking up requires synchronization technology
                    synchronized (obj){
                        System.out.println("The boss makes the buns in five seconds,Inform Customer,You can eat buns now");
                        //Once the buns are ready, call the notify method to wake up the customer to eat the buns
                        //obj.notify();//If there are multiple waiting threads, wake up one at random
                        obj.notifyAll();//Wake up all waiting threads
                    }
                }
            }
        }.start();
    }
}

Posted by MarcB on Fri, 08 Oct 2021 09:22:22 -0700