[java advanced] 1: multi-threading

Catalog

01. Basic concepts: program, process, thread

1.1 Processes and Threads

 ​

02 Thread Creation and Use

2.1 Thread class

Two ways to create threads in the 2.2 API

2.2.1 Mode 1 inherits the Thread class

2.2.2 Exercise

Common methods in the 2.2.3 Thread class

2.2.4 Thread Scheduling

2.2.5 Implementing Runnable Interface

2.2.6 Comparison of the two modes

03 Thread Life Cycle

04 Thread Synchronization

4.1 Understanding Thread Security

4.2 Synchronization in Java Solves Thread Security

4.2.1 Synchronized code block (synchronized ()

4.2.2 Synchronizing code blocks solves security issues in implementing Runnable interfaces

4.2.3 Synchronizing code blocks solves security issues in inheriting Thread classes

4.2.4 Synchronization Method

4.2.5 Use synchronization to solve thread security issues for implementing the Runnable interface

4.2.6 Use synchronization to resolve thread security issues that inherit Thread classes

4.2.7 Summary of synchronization methods:

4.3 Thread-safe single-case mode lazy

Deadlock problem on thread 05

06 Thread Security Solution 3: lock Lock

07 Thread Communication

7.1 Similarities and differences between sleep() and wait()

7.2 Classic Example

08 JDK 5.0 New ways to create threads

8.1 Implement Callable Interface

8.2 Thread Pool

01. Basic concepts: program, process, thread

  • Program: A collection of instructions written in a language for a specific task. That is, a static piece of code, a static object.
  • Process: An execution of a program, or a running program. It is a dynamic process: a process of its own generation, existence and extinction. life cycle
    • For example: QQ in operation, the running MP3 player program is static and the process is dynamic
  • As a unit of resource allocation, each process is allocated a different memory area at runtime
  • Threads, which can be further refined into threads, are an execution path within a program.
    • A process that executes multiple threads in parallel at the same time supports multiple threads.
    • Threads are the units of dispatch and execution, each thread has its own run stack and program counters (pc), and the cost of switching threads is small.
    • Threads in a process share the same memory unit/memory address space --"They allocate objects from the same heap and can access the same variables and objects. This makes communication between threads easier and more efficient. However, system resources shared by multiple threads may pose a security risk.

1.1 Processes and Threads

 

Single and multi-core CPU s

A single-core CPU is actually a pseudo multi-threaded CPU because only one thread of tasks can be executed in a single time unit. For example: Although there are multiple lanes, but only one worker is charging at the toll station, and only a fee is collected to pass through, then the CPU is like a toll collector. If someone doesn't want to pay, the toll collector can hang him (hang him, wait until he finds out, have the money ready, and then charge). But because the CPU time unit is very short, it cannot be felt.
If it is multi-core, it will make better use of the efficiency of multi-threading. (Servers are multicore now)
A Java application java.exe, there are actually at least three threads: the main() main thread, the gc() garbage collection thread, and the exception handling thread. Of course, if an exception occurs, it will affect the main thread.

Parallel and Concurrent

  • Parallel: Multiple CPU s perform multiple tasks simultaneously. For example, many people do different things at the same time.
  • Concurrency: One CPU (using time slices) performs multiple tasks simultaneously. For example: second killing, multiple people do the same thing.

Advantages of multithreading

  1. Increase the responsiveness of the application. More meaningful for graphical interfaces and enhanced user experience.
  2. Improving CPU utilization in computer systems
  3. Improve program structure. Separate long and complex processes into multiple threads and run independently to facilitate understanding and modification

When multithreading is required

  • A program needs to perform two or more tasks simultaneously.
  • Programs need to achieve some tasks to wait for, such as user input, file read and write operations, network operations, search, and so on.
  • When you need some programs to run in the background.

02 Thread Creation and Use

The Java language JVM allows programs to run multiple threads through java.lang.Thread class to reflect. (java supports multiple threads)

Attributes of the Thread class

  • Each thread does its work through the run() method of a particular Thread object, often referring to the body of the run() method as the thread body
  • Start this thread through the start() method of the Thread object instead of calling run() directly

2.1 Thread class

constructor

Thread(): Create a new Thread object
Thread(String threadname): Create a thread and specify the thread instance name
Thread(Runnabletarget): Specifies the target object to create the thread, which implements the run method in the Runnable interface
Thread(Runnable target, String name): Create a new Thread object
 

Two ways to create threads in the 2.2 API

2.2.1 Mode 1 inherits the Thread class

  • Define a subclass that inherits the Thread class.
  • Overrides the run method in the Thread class in a subclass.
  • Thread subclass object is created, that is, thread object is created.
  • Call the thread object start method: start the thread, call the run method.
class MyThread extends Thread{
    //Override run() of the Thread class, what this thread needs to do
    @Override
    public void run() {
        for(int i = 1;i < 100;i++){
            if(i % 2 == 0){
                System.out.println(Thread.currentThread().getName() + i);  // Get Threads
            }
        }
    }
}

public class ThreadTest {
    public static void main(String[] args) {
        //3. Create subobjects of the Thread class
        MyThread t1 = new MyThread();

        //4. Call start() through this object: (1) Start the current thread; (2) JVM call run() of the current thread
        t1.start();

        //The following operations are still being performed in the main thread
        for(int i = 1;i < 100;i++){
            if(i % 2 == 0){
                System.out.println(i + "***main()***");
            }
        }
    }
}

Note

2.2.2 Exercise

/**
 * Exercise: Create two threads, one that traverses an even number less than 100 and the other that traverses an odd number less than 100

Create two Thread subclasses that override run()
 */
public class ThreadDemo {
    public static void main(String[] args) {
        MyThread m1 = new MyThread();
        m1.start();

        MyThread2 m2 = new MyThread2();
        m2.start();
    }
}
class MyThread extends Thread{
    @Override
    public void run() {
        for(int i = 0;i < 100;i++){
            if(i % 2 == 0){
                System.out.println(Thread.currentThread().getName() + ":" + i);
            }
        }
    }
}

class MyThread2 extends Thread{
    @Override
    public void run() {
        for(int i = 0;i < 100;i++){
            if(i % 2 != 0){
                System.out.println(Thread.currentThread().getName() + ":" + i);
            }
        }
    }
}

Write 2: How anonymous subclasses work

/**
 * Exercise: Create two threads, one that traverses an even number less than 100 and the other that traverses an odd number less than 100
 */
public class ThreadDemo {
    public static void main(String[] args) {

        //How to create an anonymous subclass of the Thread class
        new Thread(){
            @Override
            public void run() {
                for(int i = 0;i < 100;i++){
                    if(i % 2 == 0){
                        System.out.println(Thread.currentThread().getName() + ":" + i);
                    }
                }
            }
        }.start();

        new Thread(){
            @Override
            public void run() {
                for(int i = 0;i < 100;i++){
                    if(i % 2 != 0){
                        System.out.println(Thread.currentThread().getName() + ":" + i);
                    }
                }
            }
        }.start();
    }
}

Common methods in the 2.2.3 Thread class

*Common methods for testing Thread classes
* 1.start(): Starts the current thread, executes run() of the current thread
* 2.run(): This method in the Thread class usually needs to be overridden, in which the action to be performed by the thread being created is declared
* 3.currentThread(): Static method that returns the thread in which the current code executes
* 4.getName(): Gets the name of the current thread
* 5.setName(): Sets the name of the current thread
* 6.yield(): Releases the execution power of the current CPU
* 7.join(): Invokes the join() of thread b in thread a, where thread a enters a blocking state, and thread a does not end the blocking state until thread b is fully executed.
* 8.stop(): obsolete. Force the end of the current thread when this method is executed.
* 9.sleep(long millitime): millitime milliseconds that allow the current thread to "sleep" for a specified time. The current thread is blocked for the specified millitime milliseconds.
* 10.isAlive(): Returns boolean to determine if the thread is still alive
 */

class HelloThread extends Thread{
    @Override
    public void run() {
        for(int i = 0;i < 100; i++){

            try {
                sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            if(i % 2 == 0){
                System.out.println(Thread.currentThread().getName() + ":" + i);
            }
//            if(i % 20 == 0){
//                yield(); // Release execution from the current thread, but not necessarily successful
//            }
        }
    }

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

public class ThreadModeTest {
    public static void main(String[] args) {
        HelloThread h1 = new HelloThread("Thread : 1");

//        h1.setName("thread one");

        h1.start();

        //Name the main thread
        Thread.currentThread().setName("Main Thread");

        for(int i = 0;i < 100; i++){
            if(i % 2 == 0){
                System.out.println(Thread.currentThread().getName() + ":" + i);
            }

            if(i == 20){
                try {
                    h1.join();  // The main thread of the thread enters a blocked state until h1 finishes execution
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }

        System.out.println(h1.isAlive());
    }
}

2.2.4 Thread Scheduling

High priority preempts low priority, low priority only gets low scheduling probability, not necessarily after high priority threads

/**
 * - Thread Priority Level
 *   - MAX_PRIORITY: 10
 *   - MIN _PRIORITY: 1
 *   - NORM_PRIORITY: 5 --->Default Priority
 * - Methods involved
 *   - getPriority() : Return Thread Priority
 *   - setPriority(intnewPriority) : Change Thread Priority
 *
 *   Description: A high priority thread preempts the execution of a low priority thread cpu.
 *       However, it is only probabilistic that high-priority threads are executed with high probability.
 *       This does not mean that the lower priority threads will not be executed until the higher priority threads are executed.
 */

class HelloThread extends Thread {
    @Override
    public void run() {
        for (int j = 0; j < 100; j++) {

//            try {
//                sleep(10);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }

            if (j % 2 == 0) {
                System.out.println(getName() + ":" + getPriority() + ":" + j);
            }
        }
    }
    public HelloThread(String name){
        super(name);
    }
}

public class ThreadModeTest {
    public static void main(String[] args) {
        HelloThread h2 = new HelloThread("Thread : 1");
        h2.start();

        //Set Threaded Priority
        h2.setPriority(Thread.MAX_PRIORITY);

        //Name the main thread
        Thread.currentThread().setName("Main Thread");
        Thread.currentThread().setPriority((Thread.MIN_PRIORITY));

        for(int j = 0;j < 100; j++){
            if(j % 2 == 0){
                System.out.println(Thread.currentThread().getName() + ":" + Thread.currentThread().getPriority() + ":" + j);
            }

//            if(j == 20){
//                try {
//                    h2.join();
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
//            }
        }

        System.out.println(h2.isAlive());
    }
}

Introduce

/**
 * Example: Create three c windows to sell tickets with a total of 100 tickets
 *
 * Thread security issues exist and need to be resolved.
 */
class Windows extends Thread{

    private static int ticket = 100;  //If this is not a static variable, 300 tickets will be sold and 100 will be set per thread

    @Override
    public void run() {
        while(true){
            if(ticket > 0){
                System.out.println(getName() + ":Ticket number for sale: " + ticket);
                ticket--;
            }else{
                break;
            }
        }
    }
}

public class WindowsTest {
    public static void main(String[] args) {
        Windows t1 = new Windows();
        Windows t2 = new Windows();
        Windows t3 = new Windows();

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

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

2.2.5 Implementing Runnable Interface

* 1. Create a class that implements the Runnable interface
* 2. Implement classes to implement abstract methods in Runnable: run()
* 3. Create objects that implement classes
* 4. Pass this object as an argument to the constructor of the Thread class to create an object of the Thread class
* 5. Call start() through an object of the Thread class

//1. Create a Runnable interface class
class MThread implements Runnable{

    //2. Implement classes to implement abstract methods in Runnable: run()
    @Override
    public void run() {
        for(int i = 0;i < 100;i++){
            if(i % 2 == 0){
                System.out.println(Thread.currentThread().getName() + ":" + i);
            }
        }
    }
}

public class ThreadTest1 {
    public static void main(String[] args) {
        //3. Create objects that implement classes
        MThread m1 = new MThread();
        //4. Pass this object as an argument to the constructor of the Thread class to create an object of the Thread class
        Thread t1 = new Thread(m1);
        //5. Call start() through an object of the Thread class: (1) Start thread (2) Call run() of the current thread --> Call run() of a target of type Runnable
        t1.start();

        //Start another thread, traverse an even number within 100
        Thread t2 = new Thread(m1);
        t2.setName("Thread 2");
        t2.start();
    }
}

2.2.6 Comparison of the two modes

* In Development: Priority: Ways to implement the Runnable interface
* Reason: 1. Implemented in a way that does not have the limitation of single inheritance of classes
* * 2. This is more appropriate when multiple threads share data. (ticket sales do not need to be defined as static)
 *  
* Contact: public class Thread implements Runnable
* Same thing: both ways require rewriting run() to put the logical declaration the thread is going to execute in run().

03 Thread Life Cycle

Thread is used in JDK. The State class defines several states of a thread

New: When an object of a Thread class or its subclasses is declared and created, the new thread object is created
Ready: After the thread in the newly created state is started (), it will enter the thread queue and wait for the CPU time slice, when it is ready to run but not allocated to the CPU resource
Run: When a ready thread is scheduled and CPU resources are obtained, it enters the running state, and the run() method defines the operations and functions of the thread
Blocking: In a special case, when an input or output operation is suspended or performed manually, the CPU is released and its execution is temporarily suspended to become blocked
Death: A thread has completed all its work or has been forcibly terminated prematurely or terminated with an exception

04 Thread Synchronization

4.1 Understanding Thread Security

Ask questions:

Uncertainty in execution of multiple threads causes unstable execution results

Sharing of accounts by multiple threads can result in incomplete operations and data corruption.

 

Example 2: The same ticket and wrong ticket appear in ticket sales

class MThread implements Runnable{
    private int tickets = 100;
    @Override
    public void run() {
        while(true){
            // Entering a blockage increases the chance of a false ticket
       
            if(tickets > 0){
                try {
                    sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                System.out.println(Thread.currentThread().getName() + " Ticket selling: Ticket number is" + tickets);
                tickets--;
            }else{
                break;
            }
        }
    }
}


public class ThreadTest1 {
    public static void main (String[] args){
        // Implement Class Objects
        MThread t1 = new MThread();
        // Thread object, constructor parameter is runnable object
        Thread thread1 = new Thread(t1);
        Thread thread2 = new Thread(t1);
        Thread thread3 = new Thread(t1);
        thread1.setName("Window 1");
        thread2.setName("Window 2");
        thread3.setName("Window 3");
        // Call start
        thread1.start();
        thread2.start();
        thread3.start();

    }


}

When one thread operates on a ticket that has not been completed, the other threads participate and an error ticket (0, -1, etc.) occurs.

How to solve: Lock (similar to queuing up to the toilet)

When a thread a operates on ticketes, other threads cannot participate until the thread a operation is complete, even if a is blocked

4.2 Synchronization in Java Solves Thread Security

4.2.1 Synchronized code block (synchronized ()

//Mode 1: Synchronize Code Blocks
  synchronized(Synchronization Monitor){
      //Code that needs to be synchronized (code that manipulates shared data)

   }
  • Shared data: Data operated by multiple threads simultaneously\Variables: tickets
  • Synchronization monitor: commonly known as lock, objects of any class can act as locks
    • Requirement: Multiple threads must share the same lock
  • The synchronization method solves the thread security problem. --- Benefits*
  • When synchronizing code, only one thread can participate and other threads wait. Equivalent to a single-threaded process, inefficient. --- Limitations

4.2.2 Synchronizing code blocks solves security issues in implementing Runnable interfaces

import static java.lang.Thread.sleep;

class MThread implements Runnable{
    private int tickets = 100;
    Object obj = new Object();  // Shared locks for uniqueness
    @Override
    public void run() {
        // Object obj = new Object(); Each thread will have a new lock in it, no

        while(true){
            synchronized (obj){  // Consider using this to implement locks, since there is only one object
                if(tickets > 0){
                    try {
                        sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + " Ticket selling: Ticket number is" + tickets);
                    tickets--;
                }else{
                    break;
                }
            }

        }
    }
}


public class ThreadTest1 {
    public static void main (String[] args){
        // Implement Class Objects
        MThread t1 = new MThread();
        // Thread object, constructor parameter is runnable object
        Thread thread1 = new Thread(t1);
        Thread thread2 = new Thread(t1);
        Thread thread3 = new Thread(t1);
        thread1.setName("Window 1");
        thread2.setName("Window 2");
        thread3.setName("Window 3");
        // Call start
        thread1.start();
        thread2.start();
        thread3.start();

    }
}

4.2.3 Synchronizing code blocks solves security issues in inheriting Thread classes

class window extends Thread{
    private static  int tickets = 100;
   private static Object obj = new Object(); // This must be static
    @Override
    public void run() {
        while (true){
            synchronized(obj){
                if (tickets > 0){
                    try {
                        sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(getName() + " :Ticket number for sale" + tickets);
                    tickets--;
                }else{
                    break;
                }
            }

        }
    }
}
public class WindowTest {
    public static void main(String[] args){
        window w1 = new window();
        window w2 = new window();
        window w3 = new window();
        w1.setName("Window One");
        w2.setName("Window 2");
        w2.setName("Window Three");
        w1.start();
        w2.start();
        w3.start();
    }
}

4.2.4 Synchronization Method

4.2.5 Use synchronization to solve thread security issues for implementing the Runnable interface

class Windows3 implements Runnable {

    private int ticket = 100;

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

    public synchronized void show() { //Synchronization Monitor: this
//        synchronized (this){
            if (ticket > 0) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + ":Ticket number for sale: " + ticket);
                ticket--;
            }
//        }
    }
}

public class WindowsTest3 {
    public static void main(String[] args) {
        Windows3 w3 = new Windows3();

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

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

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

4.2.6 Use synchronization to resolve thread security issues that inherit Thread classes

/**
 * Use synchronization methods to handle thread security issues in ways that inherit the Thread class
 */
class Windows4 extends Thread {

    private static int ticket = 100;

    @Override
    public void run() {

        while (true) {

            show();
        }

    }
    private static synchronized void show(){//Synchronization Monitor: Window4.class, current class
        //private synchronized void show(){//synchronization monitor: t1,t2,t3. This solution is incorrect
        if (ticket > 0) {

            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println(Thread.currentThread().getName() + ": Ticket number:" + ticket);
            ticket--;
        }
    }
}


public class WindowsTest4 {
    public static void main(String[] args) {
        Windows4 t1 = new Windows4();
        Windows4 t2 = new Windows4();
        Windows4 t3 = new Windows4();


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

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

    }
}

4.2.7 Summary of synchronization methods:

* 1. Synchronization methods still involve synchronization monitors, but we don't need to explicitly declare them.
* 2. Non-static synchronization method, synchronization monitor is:
* Static synchronization method, synchronization monitor is: current class itself (inherited class, generally static data and static method)

4.3 Thread-safe single-case mode lazy

/**
 * Use synchronization to override lazy behavior in singleton mode to thread-safe
 */
public class BankTest {
}

class Bank{
        // Privatization Constructor

    private Bank(){}
        // Instances of classes constructed internally and must be static

    private static Bank instance = null;
   // Provide a public method to return an instance

    public static Bank getInstance(){
        //Mode 1: Slightly less efficient
        //Shortcut: Alt+Shift+Z
//        synchronized (Bank.class) {
//            if(instance == null){
//                instance = new Bank();
//            }
//            return instance;
//        }

        //Mode 2: Higher efficiency
        if(instance == null) {
            synchronized (Bank.class) {
                if (instance == null) {  // Double check lock
                    instance = new Bank();
                }
            }
        }
        return instance;
    }
}

Deadlock problem on thread 05

import static java.lang.Thread.sleep;

public class ThreadTEST {
    /*
Demonstrate thread deadlock issues
 */
        public static void main(String[] args) {

            StringBuffer s1 = new StringBuffer();
            StringBuffer s2 = new StringBuffer();

            new Thread() {
                @Override
                public void run() {
                    synchronized (s1) {
                        s1.append('a');
                        s2.append("1");
                        // Examples deadlock, no output, unable to execute
                        try {
                            sleep(100);
                        }catch (InterruptedException e){
                            e.printStackTrace();
                        }

                        synchronized (s2) {
                            s1.append("b");
                            s2.append("2");

                            System.out.println(s1);
                            System.out.println(s2);
                        }


                    }
                }

            }.start();
                // Anonymous object implementing Runnabel interface
            new Thread(new Runnable() {
                @Override
                public void run() {
                    synchronized (s2) {
                        s1.append('c');
                        s2.append("3");
                        try {
                            sleep(100);
                        }catch (InterruptedException e){
                            e.printStackTrace();
                        }

                        synchronized (s1) {
                            s1.append("d");
                            s2.append("4");

                            System.out.println(s1);
                            System.out.println(s2);
                        }

                    }

                }
            }).start();

        }
}

/*No sleep output
ab
12
abcd
1234,Maybe Thread2 does it first, outputting 12, ab, cdab, 3412
 */

06 Thread Security Solution 3: lock Lock

import java.util.concurrent.locks.ReentrantLock;

/*
Solve thread security method three: lock lock lock
 Declare an attribute in the thread to make a ReentrantLoc object
synchronized Similar to lock:
Same: Both can solve thread security issues
 Different:
1: lock()Synchronization needs to be started and ended manually, and synchronized automatically releases the synchronization monitor after executing the corresponding synchronization code
2.lock()Only code block locks, sychronized has method block locks and method houses
3. lock Locks have radically better performance
 */
class Window implements Runnable{
    private int tickets = 100;
    // 1. Declare an attribute in the thread and instantiate a ReentrantLoc object
    private ReentrantLock lock = new ReentrantLock();

    @Override
    public void run() {
        while(true){
            try{
                // 2. Call lock()
                lock.lock();
                if(tickets > 0){
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "Sell ticket, Ticket number is:" + tickets);
                    tickets--;
                }else{
                    break;
                }
            }finally {
                // 3. Call 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.start();
       t2.start();
       t3.start();

    }


}

Synchronization Exercise

/**
 * The bank has an account.
 * Two depositors each deposit 3,000 yuan into the same account, 1,000 at a time and 3 times.
 * Print account balance is saved each time.
 *
 * Analysis:
 *      1.Is it a multithreaded problem? Yes, two stored threads
 *      2.Is there shared data? Yes, account (or balance)
 *      3.Are there any thread security issues? Yes
 *      4.How do I resolve thread security issues? Synchronization mechanism: There are three ways.
 */
class Account{
    private double balance;

    public Account(double balance){
        this.balance = balance;
    }

    //Save money, synchronization solution inheritance multi-threading should be used with caution
    public synchronized void deposit(double amt){
        if(amt > 0){

            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            balance += amt;
            System.out.println(Thread.currentThread().getName() + ":" + "Successful Savings, Current Balance:" + balance);
        }
    }
}

class Customer extends Thread{

    private Account acct;
    public Customer(Account acct){
        this.acct = acct;
    }

    @Override
    public void run() {

        for(int i = 0;i < 3;i++){
            acct.deposit(1000);
        }
    }
}

public class AccountTest {
    public static void main(String[] args) {
        Account acct = new Account(0);
        Customer c1 = new Customer(acct);
        Customer c2 = new Customer(acct);

        c1.setName("nail");
        c2.setName("B");

        c1.start();
        c2.start();
    }
}

07 Thread Communication

Example 1

Three methods involved:
* wait(): Once this method is executed, the current thread is blocked and the synchronization monitor is released. o1.wait();
* notify(): Once this method is executed, a thread that is waited is awakened. If more than one thread is waiting, wake up the one with the highest priority.
* notifyAll(): Once this method is executed, all wait ed threads are awakened.
 *
*Instructions:
* * 1. The wait (), notify(), and notifyAll() methods must be used in the synchronization block or synchronization method.
* * 2. The caller of the wait (), notify(), notifyAll() methods must be a synchronization monitor in the synchronization block or method. Otherwise, IllegalMonitorStateException exception will occur
* * 3.wait(), notify(), notifyAll() are defined in java. In the lang.Object class.

/*
Print 1 100 using two threads. Thread 1, Thread 2 Alternate Printing
 */
class Number extends Thread{
    private  static int number = 1;
    public static Object o1 = new Object();
    @Override
    public void run() {
        while(true){
            synchronized (o1){
                o1.notify();//Wake up the current thread, if you do not add o1, error will occur!

                if(number <= 100){
                    try {
                        sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "Print:" + number);
                    number++;
                    try {

                        // Causes threads that use the current wait to become blocked
                        o1.wait();  //Release lock
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }else{
                    break;
                }
            }

        }
    }
}

public class ComunicationTest {
    public static void main(String[] args){
        Number number1 = new Number();
        Number number2 = new Number();

        number1.setName("Thread 1");
        number2.setName("Thread 2");

        number1.start();
        number2.start();


    }

}

7.1 Similarities and differences between sleep() and wait()

*Interview Question: What are the similarities and differences between sleep() and wait()?
* 1. Same point: Once a method is executed, the current thread can be blocked.
* 2. The differences are as follows: 1) The positions of the two method declarations are different: sleep () is declared in the Thread class and wait() in the Object class.
* * 2) Calls require different requirements: sleep() can be called in any desired scenario. wait() must be used in a synchronization block or synchronization method
* * 3) Regarding whether to release the synchronization monitor: if both methods are used in the synchronization block or synchronization method, sleep() will not release the lock (synchronization monitor), wait() will release the lock.

7.2 Classic Example

 

/*
1.Is it a multithreaded problem: Yes, producer and consumer threads
2.Is there shared data: Yes, clerk, product
3.How to solve: Three methods of synchronization
4.Communication: wait (); notify(); Yes, if more than 20, block the thread
 */
class Clerk{
    private int productNum = 0;

    //yield a product
    public synchronized void productProduct() {
        if(productNum < 20){
            productNum++;
            System.out.println(Thread.currentThread().getName() +
                    "Start production " + productNum + "Products");
            // After using wait, add notify, if not, the consumer will remain blocked
            notify();

        }else{
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    //Consumer Products
    public synchronized void consumeProduct() {
        if(productNum > 0){
            System.out.println(Thread.currentThread().getName() + "Start Consuming "
                    + productNum + "Products");
            productNum--;
            notify();
        }else{
            //Only one clerk object was created from start to finish, so locks are shared
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }
}
class Producer extends Thread{ //Producer
    private Clerk clerk;

    public Producer(Clerk clerk) {
        this.clerk = clerk;
    }

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + "Start production");
        while(true){
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            clerk.productProduct();
        }

    }
}

class Customer extends Thread {//Consumer
    private Clerk clerk;

    public Customer(Clerk clerk) {
        this.clerk = clerk;
    }

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + "Start Consuming");
        while(true){
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            clerk.consumeProduct();
        }

    }
}

public class ProductTest {
    public static void main(String[] args){
        Clerk clerk = new Clerk();

       Producer p1 =  new Producer(clerk);
       p1.setName("Producer");

       Customer c1 = new Customer(clerk);
       c1.setName("Consumer");

       p1.start();
       c1.start();


    }

}

08 JDK 5.0 New ways to create threads

8.1 Implement Callable Interface

 

/*
Mode 3: Ways to implement Callable interface
1.Create an implementation class that implements the Callable interface
2.Implement the call method, declare the action this thread needs to perform in the call method, and call needs to return a value
3.Create callanle implementation class object
4. Pass this implementation class object as a parameter into the FutherTask constructor to create the FutherTask object
5,Pass the futherTask object as an argument to the Thread class constructor and call the Start method
 */

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
//1. Create an implementation class that implements the Callable interface
class NumberThread implements Callable {

    @Override
    //2. Implement the call method, declare the action this thread needs to perform in the call method, and call needs to return a value
    public Object call() throws Exception {
        int sum = 0;
        for(int i = 1; i <= 100; i++){
            if (i % 2 ==0){
                System.out.println(i);
                sum += i;
            }
        }
        return sum;// Boxed here
    }
}
public class CallableTest {
    public static void main(String[] args){
        // 3. Create callanle implementation class object
        NumberThread numberThread = new NumberThread();
        //4. Create a FutherTask object by passing this implementation class object as a parameter to the FutherTask constructor
        FutureTask futureTask = new FutureTask(numberThread);//Implementation Class of Callable

       // 5, pass the futherTask object as an argument to the Thread class constructor and call the Start method
        new Thread(futureTask).start();

        try {
            // get() return value is an overridden return value
            Object sum = futureTask.get();
            System.out.println(sum);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

    }


}

8.2 Thread Pool

 

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * Four ways to create multithreads: using thread pools
 *
 * Benefits:
 *      1.Increase response speed (reduces time to create new threads)
 *      2.Reduce resource consumption (reuse threads in the thread pool, do not need to be created every time)
 *      3.Easy Thread Management
 *          corePoolSize: Core pool size
 *          maximumPoolSize: Maximum Threads
 *          keepAliveTime: The maximum amount of time a thread can remain without a task before it terminates
 *
 * Interview Question: How many ways to create multithreads? Four!
 */

class NumberThread implements Runnable{
    @Override
    public void run() {
        for(int i = 0;i <= 100;i++){
            if(i % 2 == 0){
                System.out.println(Thread.currentThread().getName() + ":" + i);
            }
        }
    }
}

class NumberThread1 implements Runnable{
    @Override
    public void run() {
        for(int i = 0;i <= 100;i++){
            if(i % 2 != 0){
                System.out.println(Thread.currentThread().getName() + ":" + i);
            }
        }
    }
}

public class ThreadPool {
    public static void main(String[] args) {

        //1. Provide a thread pool with a specified number of threads
        ExecutorService service = Executors.newFixedThreadPool(10);
        ThreadPoolExecutor service1 = (ThreadPoolExecutor) service; //Turn Strongly
        //Set Thread Pool Properties
//        System.out.println(service.getClass());
//        service1.setCorePoolSize(15);
//        service1.setKeepAliveTime();

        //2. Perform the operation of the specified thread. An object that implements a Runnable or Callable interface implementation class is required
        service.execute(new NumberThread());  //Suitable for Runable
        service.execute(new NumberThread1());  //Suitable for Runable

//        service.submit(Callable callable); // Suitable for Callable

        //3. Close connection pool
        service.shutdown();
    }
}

Keywords: Java Back-end

Added by Kudose on Wed, 23 Feb 2022 19:04:10 +0200