directory

  • Java three soul seven soul – advanced multithreading
    • One, the creation of multiple threads
    • Second, thread safety
    • Third, thread communication problem
    • More examples
      • 1. Use thread synchronization method to solve the singleton mode thread safety problem
      • 2. Bank deposit issues (thread safety issues)
      • 3. Producer-consumer issues (thread communication issues)

One, the creation of multiple threads

== There are four ways to create multithreading!! = =

1. Create a Thread subclass

Code first:

/** * Create Thread subclass **@author๐Ÿนโ˜‚เฟˆ Autumn duck เฟˆ๐Ÿน โ˜‚เฟˆ *@create2020/3/7 now * /

/ / thread class
class NumCount extends Thread{

    // The run method is the code to execute
    @Override
    public void run(a) {
        //่พ“ๅ‡บ0-99
        for (int i = 0; i < 100; i++) {
           System.out.println(NumCount.currentThread().getName()+":"+i); }}}/ / the main class
public class MyThread {
    public static void main(String[] args) {
        // Create an object that subclasses Thread
        NumCount nc1 = new NumCount();
        // Give the thread a name
        nc1.setName("Count thread 1");
        // Start the threadnc1.start(); }}Copy the code

Matters needing attention

  • The run() method is the execution content of the thread
  • The object created requires a call to the start() method to start the thread (inheritance)
  • NumberCount. CurrentThread (). The getName () is to obtain the name of the current thread (inheritance)

2. Implement the Runnable interface

Code first:

/** * Implement the Runnable interface **@author๐Ÿนโ˜‚เฟˆ Autumn duck เฟˆ๐Ÿน โ˜‚เฟˆ *@create2020/3/7 now * /

/ / thread class
class NumCount implements Runnable{

    // The run method is the code to execute
    @Override
    public void run(a) {
        //่พ“ๅ‡บ0-99
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName()+":"+i); }}}/ / the main class
public class MyThread {
    public static void main(String[] args) {
        // Instantiate the Runnable interface
        NumCount numberCount = new NumCount();
        // Instantiate a thread. The constructor takes the instantiated interface as an argument
        Thread nc1 = new Thread(numberCount);
        // Give the thread a name
        nc1.setName("Count thread 1");
        // Start the threadnc1.start(); }}Copy the code

Matters needing attention

  • Since we implement the Runnable interface, we cannot use the NunberCount class to get the thread name
  • When creating a thread, you instantiate the interface and then create the thread object

3. Implement the Callable interface

Code first:

/** ** Create multithreading method 3: * implement Callable interface -- new ** in JDK5.0@author๐Ÿนโ˜‚เฟˆ Autumn duck เฟˆ๐Ÿน โ˜‚เฟˆ *@create2020/3/7 now * /

/ / thread class
class NumCount implements Callable<Integer> {

    // Override the call() method
    @Override
    public Integer call(a) throws Exception {
        // Calculate the sum of the numbers from 1 to 100
        int sum = 0;
        for (int i = 1; i <= 100; i++) {
            System.out.println(Thread.currentThread().getName() + ":" + i);
            sum += i;
        }
        returnsum; }}/ / the main class
public class MyThread {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // Create an object for the Callable interface implementation class
        NumCount numCount = new NumCount();
        // Create the FutureTask object by passing the object of the Callable interface implementation class to the FutureTask constructor
        FutureTask<Integer> futureTask = new FutureTask<>(numCount);
        // Create a Thread and pass the FutureTask object into the Thread constructor
        Thread nc1 = new Thread(futureTask);
        nc1.setName("Count thread 1");
        nc1.start();

        // Get the return value of the call method in Callable
        Integer sum = futureTask.get();
        System.out.println("The sum is:"+ sum); }}Copy the code

Matters needing attention

  • The Callable method was updated in JDK 1.5
  • FutureTask implements the Runnab interface, so you can pass in an instantiated object of FutureTask when creating a thread
  • Callable is more flexible than Runnable, supports generics, and can return values
  • The return value of the call() method is retrieved by FutureTask’s get() method

4. Create a thread pool

Code first:

/** * Create thread pool **@author๐Ÿนโ˜‚เฟˆ Autumn duck เฟˆ๐Ÿน โ˜‚เฟˆ *@create2020/3/7 now * /

/ / thread class
class NumCount implements Runnable {

    // Override the run method
    @Override
    public void run(a) {
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + ":"+ i); }}}/ / the main class
public class MyThread {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // Create a thread pool with the specified number of threads
        ExecutorService service = Executors.newFixedThreadPool(10);
        // To perform operations on the specified thread, provide an object that implements the Runnable or Callable interface implementation class
        service.execute(new NumCount());/ / for Runnable
// service.submit(); / / for Callable
        // Close the thread poolservice.shutdown(); }}Copy the code

Matters needing attention

  • Thread pools support Runnable and Callable objects
  • See another thread pool tutorial for details

Second, thread safety

Problem introduction:

  • Train ticket problem: three ticket Windows sell 100 tickets at once

Problem analysis:

  1. Buying tickets for three Windows at the same time requires multi-threading
  2. There is one shared piece of data during the buying process: the number of tickets
  3. Thread-safety issues occur during execution: selling the same ticket twice and selling the wrong ticket

Q: Why is there a double wrong ticket? A: When the extreme case occurs: when multiple threads call the shared data at the same time, and the thread is not finished, there will be the situation of repeatedly fetching the same value (duplicate vote), when the number of votes does not meet the number of threads, there will be A negative number (wrong vote).

Solution: Thread synchronization mechanism

Thread synchronization: When one thread is using shared data (executing synchronized code), other threads wait, whether the thread is blocked or not.

If you don't understand, just imagine the women lining up in front of the women's restroom at a tourist attraction.Copy the code

Specific measures:

1. This method involves the synchronized modifier. Basic format:

synchronized(Synchronization monitor (lock)){*// The code to be synchronized*}Copy the code

Description:

  1. The code that operates on shared data is the code to be synchronized
  2. Shared data: The same data that multiple threads work on together
  3. Synchronization monitors, commonly known as locks, can be used by objects of any class.
  4. Synchronized threads must share a lock

Example:

/** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** * * * *@author๐Ÿนโ˜‚เฟˆ Autumn duck เฟˆ๐Ÿน โ˜‚เฟˆ *@createPrevailed 2020/3/5 Philistine * /

class TicketTread extends Thread{

    // To ensure that multiple threads share the same data, set it to static
    public static int ticket = 100;
    // Same lock
    public static Object object = new Object();

    @Override
    public void run(a) {
        while (true) {// Synchronize code blocks
            synchronized (object){
                if (ticket>0) {try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(TicketTread.currentThread().getName() + ": selling no." + ticket + "Ticket");
                    ticket--;
                }else{
                    break;
                }
            }
        }
    }
}


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

        t1.setName("Window one");
        t2.setName("Window two");
        t3.setName("Window three"); t1.start(); t2.start(); t3.start(); }}Copy the code

This method involves the synchronized modifier. Basic format:

synchronizedData type method name (){// The code to be synchronized
}
Copy the code

Note:

  • There is also a synchronization monitor (lock) at this time, which defaults to this

Example:

class Windows1 implements Runnable{

    // There is no need to set static variables because multiple threads call the same interface
    public int ticket = 100;
    Object object = new Object();

    @Override
    public void run(a) {
        while (true){ show(); }}// Synchronize methods
    public synchronized void show(a){
        if (ticket>0) {try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println(TicketTread.currentThread().getName() + ": selling no." + ticket + "Ticket"); ticket--; }}}public class TicketDemo2 {
    public static void main(String[] args) {
        Windows1 windows = new Windows1();
        Thread t1 = new Thread(windows);
        Thread t2 = new Thread(windows);
        Thread t3 = new Thread(windows);

        t1.setName("Window one");
        t2.setName("Window two");
        t3.setName("Window three"); t1.start(); t2.start(); t3.start(); }}Copy the code

3. The ReentrantLock JDK1.5 new feature is similar to synchronizing code blocks. Replace code blocks with calls to methods. Example:

class Windows implements Runnable{

    public static int ticket = 100;
    private ReentrantLock lock = new ReentrantLock();

    @Override
    public void run(a) {
        while (true) {try {

                // Call the locked method
                lock.lock();

                // The code after the lock is equivalent to synchronizing the code block

                if (ticket > 0) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + ": selling no." + ticket + "Ticket");
                    ticket--;
                } else {
                    break; }}finally {
                // Call the unlock methodlock.unlock(); }}}}public class LockTest {
    public static void main(String[] args) {
        Windows windows = new Windows();
        Thread t1 = new Thread(windows);
        Thread t2 = new Thread(windows);
        Thread t3 = new Thread(windows);

        t1.setName("Window one");
        t2.setName("Window two");
        t3.setName("Window three"); t1.start(); t2.start(); t3.start(); }}Copy the code

Interview question: The difference between synchronized and Lock?

  • Similarities: thread synchronization mechanism is implemented
  • Difference:
    • The Synchornized mechanism automatically releases the synchronization monitor after the corresponding synchronization code is executed.
    • Lock starts synchronization manually (lock()) and ends synchronization manually (unlock())

Third, thread communication problem

Problem introduction:

Two threads print 1-100, alternately printing the problem code:

/** * Two threads print 1-100, alternate **@author๐Ÿนโ˜‚เฟˆ Autumn duck เฟˆ๐Ÿน โ˜‚เฟˆ *@create2020/3/6 22:41 * /

class Number implements Runnable{

    private int number = 1;

    @Override
    public void run(a) {
        while (true) {synchronized (this) {
                if (number<=100) {try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + ": number:" + number);
                    number++;
                }else {
                    break;
                }
            }
        }
    }
}

public class Communicate {
    public static void main(String[] args) {
        Number number = new Number();
        Thread t1 = new Thread(number);
        Thread t2 = new Thread(number);

        t1.setName(Thread 1 "");
        t2.setName(Thread 2 ""); t1.start(); t2.start(); }}Copy the code

When you run this code, only a single thread will run

Problem analysis:

The T1 thread uniformly occupies the lock and cannot print alternately

Solution: Thread communication

Three swordsmen are required: wait(), notify(), and notifyAll()

  • Wait (): Once this method is executed, the current thread blocks and releases the synchronization monitor (lock)
  • Notify (): Once this method is executed, it wakes up one of the threads being waited or, if there are more than one threads being waited, the one with the highest priority.
  • NotifyAll (): Once this method is executed, all threads being waited are awakened.

Description:

  1. Three methods must be used in synchronized code blocks or synchronized methods
  2. Three methods of the caller, must be synchronized code block or synchronization method of synchronous monitor (lock to the caller, only lock can call three method) otherwise, there will be a IllegalMonitorStateException anomalies
  3. Three methods are defined in the java.lang.Object class

Specific measures:

/** * Two threads print 1-100, alternate **@author๐Ÿนโ˜‚เฟˆ Autumn duck เฟˆ๐Ÿน โ˜‚เฟˆ *@create2020/3/6 22:41 * /

class Number implements Runnable{

    private int number = 1;

    @Override
    public void run(a) {
        while (true) {synchronized (this) {
                // Wake up the thread with notify()
// this.notify();
                notify();
                if (number<=100) {try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + ": number:" + number);
                    number++;

                    try {
                        // Use wait() to block a thread
// this.wait();
                        wait();
                    } catch(InterruptedException e) { e.printStackTrace(); }}else {
                    break;
                }
            }
        }
    }
}

public class Communicate {
    public static void main(String[] args) {
        Number number = new Number();
        Thread t1 = new Thread(number);
        Thread t2 = new Thread(number);

        t1.setName(Thread 1 "");
        t2.setName(Thread 2 ""); t1.start(); t2.start(); }}Copy the code

What are the similarities and differences between sleep() and wait()?

  • Similarities: Once a method is executed, it can cause the current thread to block
  • Difference:
    • The two methods declare sleep() in Thread and wait() in Object.
    • The call requirements are different: Sleep () can be called in any scenario where it is needed. Wait () must be used in synchronized code blocks and synchronized methods
    • On whether to release the synchronization monitor: If both methods are used in synchronized code blocks or synchronized methods, sleep() does not release the lock, and wait() does

More examples

1. Use thread synchronization method to solve the singleton mode thread safety problem

Problem solving:

/** * Use thread synchronization to solve singleton thread safety problems **@author๐Ÿนโ˜‚เฟˆ Autumn duck เฟˆ๐Ÿน โ˜‚เฟˆ *@create2020/3/6 roar, * /
public class BankDemo {}class Bank{
    // Singleton (private constructor, making sure the class uses object uniqueness)
    private Bank(a){};

    public static Bank instence = null;

    Thread-safety issues may be raised here
    public static Bank getInstence(a){

        // All threads are synchronized.
// synchronized (Bank.class) {
// if (instence==null){
// instence = new Bank();
/ /}
// return instence;
/ /}
        // Method 2: High efficiency (a small number of threads are synchronized)
        if (instence==null) {synchronized (Bank.class) {
                if (instence==null){
                    instence = newBank(); }}}returninstence; }}Copy the code

2. Bank deposit issues (thread safety issues)

Problem description: There is an account in the bank, and two depositors deposit 3000 yuan to the same account respectively. Each deposit is 1000 yuan, and each deposit is three times, and the balance of each deposit is printed. Problem solving:

/ * * *@author๐Ÿนโ˜‚เฟˆ Autumn duck เฟˆ๐Ÿน โ˜‚เฟˆ *@create2020/3/6 "* /

// Account (shared data)
class Account{

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

    / / save
    public synchronized void deposit(double amt){

        if (amt > 0){
            balance += amt;
            System.out.println(Thread.currentThread().getName() + ": Save successfully! The current balance is:+ balance); }}}// Depositor (thread)
class Customer implements Runnable{

    private Account acct;
    // Initialize the data
    public Customer(Account acct){
        this.acct = acct;
    }

    @Override
    public void run(a) {
        for (int i = 0; i < 3; i++) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            acct.deposit(1000); }}}public class AccountTest {
    public static void main(String[] args) {
        Account acct = new Account(0);
        Customer customer = new Customer(acct);
        Thread c1 = new Thread(customer);
        Thread c2 = new Thread(customer);

        c1.setName("็”ฒ");
        c2.setName("ไน™"); c1.start(); c2.start(); }}Copy the code

3. Producer-consumer issues (thread communication issues)

The Productor gives the product to the Clerk, and the Customer takes the product from the Clerk. The shop assistant can only hold a fixed number of products (e.g., 20) at a time. If the producer tries to produce more products, the shop assistant will ask the producer to stop for a while. If there is no product in the store, the clerk will tell the consumer to wait, if there is a product in the store to inform the consumer to pick up the product. Problem analysis:

1. Is it multithreading? Yes, producer thread, consumer thread 2. Is there any shared data? Yes, clerk (or product) 3. How to solve off-the-shelf security problems? Synchronization mechanism, there are three methods 4. Whether to design thread communication? is

Problem solving:

/ * * *@author๐Ÿนโ˜‚เฟˆ Autumn duck เฟˆ๐Ÿน โ˜‚เฟˆ *@create2020/3/7 11:04 * /
class Clerk{

    private int productCount = 0;

    // Make a product
    public synchronized void produceProduct(a) {
        if (productCount<20){
            productCount++;
            System.out.println(Thread.currentThread().getName() + ": in production" + productCount + "One product");
            notify();
        }else {
            try {
                wait();
            } catch(InterruptedException e) { e.printStackTrace(); }}}// Consumer products
    public synchronized void consumeProduct(a){
        if (productCount>0){
            System.out.println(Thread.currentThread().getName() + ": consuming the first" + productCount + "One product");
            productCount--;
            notify();
        }else {
            try {
                wait();
            } catch(InterruptedException e) { e.printStackTrace(); }}}}class Producer implements Runnable{/ / producer

   private Clerk clerk;

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

    @Override
    public void run(a) {
        System.out.println(Thread.currentThread().getName() + ": Start production....");

        while (true) {try {
                Thread.sleep(10);
            } catch(InterruptedException e) { e.printStackTrace(); } clerk.produceProduct(); }}}class Consumer implements Runnable{/ / consumer

    private Clerk clerk;

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

    @Override
    public void run(a) {
        System.out.println(Thread.currentThread().getName() + ": Start consuming products....");

        while (true) {try {
                Thread.sleep(20);
            } catch(InterruptedException e) { e.printStackTrace(); } clerk.consumeProduct(); }}}public class Product {
    public static void main(String[] args) {
        Clerk clerk = new Clerk();

        Producer producer = new Producer(clerk);
        Thread p1 = new Thread(producer);
        p1.setName("Producer 1");

        Consumer consumer = new Consumer(clerk);
        Thread c1 = new Thread(consumer);
        c1.setName("Consumer 1");
        Thread c2 = new Thread(consumer);
        c2.setName("Consumer 2"); p1.start(); c1.start(); c2.start(); }}Copy the code