How can the 38 year old middle-aged unemployed live? Java basic interview question - multithreading

[](

)Callable thread creation

public class CallableTest {

	public static void main(String[] args) throws ExecutionException,InterruptedException {

        // new Thread(new Runnable()).start();

        // new Thread(new FutureTask<V>()).start();

        // new Thread(new FutureTask<V>( Callable )).start();

        new Thread().start(); // How do I start Callable

        MyThread thread = new MyThread();

        FutureTask futureTask = new FutureTask(thread); // Adaptation class

        new Thread(futureTask,"A").start();

        new Thread(futureTask,"B").start(); // The results are cached and efficient

        Integer o = (Integer) futureTask.get(); //This get method may cause blocking! Put him in

        last

        // Or use asynchronous communication to process!

        System.out.println(o);

	}

}

class MyThread implements Callable<Integer> {

    @Override

    public Integer call() {

        System.out.println("call()"); // Several call s will be printed

        // Time consuming operation

        return 1024;

	}

} 

[](

)Thread pool

White whoring data

The top-level interface of thread pool in Java is Executor, but strictly speaking, Executor is not a thread pool, but just a tool for executing threads. The real thread pool interface is ExecutorService.

Thread pool: three methods, seven parameters and four rejection strategies

[](

)Benefits of thread pooling

  • Reduce resource consumption

  • Improve response speed

  • Easy to manage.

[](

)Three methods

  • Executors. Newsinglethreadexecution() creates a thread to execute

  • Executors.newFixedThreadPool(Int i) creates I threads to execute

  • Executors.newCachedThreadPool() cache pool, scalable, strong in case of strength and weak in case of weakness

Create code:

public static void main(String[] args) {

        ExecutorService threadPool = Executors.newSingleThreadExecutor();// Single thread

        //ExecutorService threadPool = Executors.newFixedThreadPool(5); //  Create a fixed thread pool size

        //ExecutorService threadPool = Executors.newCachedThreadPool(); //  Scalable, strong in case of strength, weak in case of weakness

        try {

            for (int i = 0; i < 100; i++) {

                // After using thread pool, use thread pool to create threads

                threadPool.execute(()->{

                    System.out.println(Thread.currentThread().getName()+" ok");

                });

            }

        } catch (Exception e) {

            e.printStackTrace();

        } finally {

            // When the thread pool runs out, the program ends. Close the thread pool

            threadPool.shutdown();

        }

    } 

Seven parameters

Source code analysis of three methods:

public static ExecutorService newSingleThreadExecutor() {

    return new FinalizableDelegatedExecutorService

    (new ThreadPoolExecutor(1, 1,0L, TimeUnit.MILLISECONDS,

    new LinkedBlockingQueue<Runnable>()));

}

public static ExecutorService newFixedThreadPool(int nThreads) {

    return new ThreadPoolExecutor(5, 5,

    0L, TimeUnit.MILLISECONDS,

    new LinkedBlockingQueue<Runnable>());

}

public static ExecutorService newCachedThreadPool() {

    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,

    60L, TimeUnit.SECONDS,

    new SynchronousQueue<Runnable>());

}

//All three methods return the ThreadPoolExecutor() class 

Source code analysis of ThreadPoolExecutor (seven parameters):

public ThreadPoolExecutor(

    int corePoolSize, // Core thread pool size

    int maximumPoolSize, // Maximum core thread pool size

    long keepAliveTime, // If no one calls it, it will be released

    TimeUnit unit, // Timeout unit

    BlockingQueue<Runnable> workQueue, // Blocking queue

    ThreadFactory threadFactory, // Thread factory: it is used to create threads. Generally, it does not need to be moved

    RejectedExecutionHandler handle // Reject Policy){

        if (corePoolSize < 0 ||maximumPoolSize <= 0 ||maximumPoolSize < corePoolSize ||

        keepAliveTime < 0)

        	throw new IllegalArgumentException();

        if (workQueue == null || threadFactory == null || handler == null)

        	throw new NullPointerException();

        this.acc = System.getSecurityManager() == null ?null:AccessController.getContext();

        this.corePoolSize = corePoolSize;

        this.maximumPoolSize = maximumPoolSize;

        this.workQueue = workQueue;

        this.keepAliveTime = unit.toNanos(keepAliveTime);

        this.threadFactory = threadFactory;

        this.handler = handler;

} 

Four rejection strategies

White whoring data

image-20210527134117484



/**

 * new ThreadPoolExecutor.AbortPolicy()         //When the bank is full, someone else comes in. If you don't deal with this person, throw an exception

 * new ThreadPoolExecutor.CallerRunsPolicy()    //Where to go!

 * new ThreadPoolExecutor.DiscardPolicy()       //If the queue is full, lose the task and no exception will be thrown!

 * new ThreadPoolExecutor.DiscardOldestPolicy() //When the queue is full, try to compete with the earliest, and no exception will be thrown

 * 

[](

)Thread lifecycle (state)

When a thread is created and started, it neither enters the execution state as soon as it is started, nor is it always in the execution state

public enum State {

// At this time, only the JVM allocates memory for it and initializes the value of its member variable

    NEW,

// After calling the start() method, the thread is running, and the Java virtual opportunity creates a method call stack and a program counter for it, waiting for the scheduled run

    RUNNABLE,

// block

    BLOCKED,

// Wait, wait, wait

    WAITING,

// Timeout wait

    TIMED_WAITING,

// termination

    TERMINATED;

} 

[](

)Thread termination method

In addition to normal exit, there are three ways to end a thread

  • Set the exit flag to make the thread exit normally, that is, when the run() method is completed, the thread terminates

  • Interrupt the thread using the interrupt() method

  • Use the stop method to forcibly terminate the thread (not recommended)

1. Use the exit flag to terminate the thread

The most direct way is to set a boolean flag and control whether the while loop exits by setting this flag to true or false

public class ThreadSafe extends Thread {

    public volatile boolean exit = false; 

        public void run() { 

        while (!exit){

            //do something

        }

    } 

} 

2. Interrupt the current thread with the interrupt() method

White whoring data

There are two ways to interrupt a thread using the interrupt() method:

  1. The thread is in a blocking state. When calling the thread's interrupt() method, an interrupt exception will be thrown. The method in the block throws the exception, catches the exception through the code, and then break s out of the loop state, giving us a chance to end the execution of the thread.

  2. If the thread is not in the blocking state, use isInterrupted() to judge the interrupt flag of the thread to exit the loop.

Code demonstration:

//First case

public class ThreadSafe extends Thread {

    public void run() { 

        while (true){

            try{

                    Thread.sleep(5*1000);//Blocking 5 wonderful

                }catch(InterruptedException e){

                    e.printStackTrace();

                    break;//After the exception is caught, execute break to jump out of the loop.

                }

        }

    } 

}



//The second case

public class ThreadSafe extends Thread {

    public void run() { 

        while (!isInterrupted()){

            //do something, but no throw InterruptedException

        }

    } 

} 

3. Use the stop method to terminate the thread

Thread can be used directly in the program Stop () to forcibly terminate the thread, but the stop method is very dangerous

Unsafe mainly include:

thread. After the stop () call, the thread creating the child thread will throw the ThreadDeath error error and release all locks held by the child thread. Generally, any lock code block is used to protect the consistency of data, if thread. Is called If all locks held by this thread are released suddenly (uncontrollable) after stop (), the protected data may be inconsistent, and other threads may cause some strange application errors when using these corrupted data.

[](

)Java thread lock

[](

)Optimistic lock

White whoring data

Optimistic locking is an optimistic idea, that is, it thinks that there are more reads and fewer writes, and the possibility of concurrent writes is low. Every time you get the data, you think others will not modify it, so you won't lock it. However, when updating, you will judge whether others have updated the data during this period, and take the operation of reading the current version number first and then locking it, If it fails, repeat the read compare write operation.

Optimistic locks in java are basically implemented through CAS operation, which is an updated atomic operation

[](

)Pessimistic lock

Pessimistic locking is a pessimistic idea, that is, it is considered that there are many writes and there is a high possibility of concurrent writes. Every time you go to get the data, you think others will modify it, so you will lock it every time you read and write the data, so that others will block the data until they get the lock.

The pessimistic lock in java is Synchronized

[](

)Spin lock

If the thread holding the lock can release the lock resources in a very short time, those threads waiting for the competing lock do not need to switch between the kernel state and the user state to enter the blocking pending state. They only need to wait (spin) and obtain the lock immediately after the thread holding the lock releases the lock, so as to avoid the consumption of switching between the user thread and the kernel

[](

)Advantages and disadvantages

Spin lock_ Minimize thread blocking,

This can greatly improve the performance of code blocks that do not have fierce lock competition and occupy a very short lock time, because the consumption of spin will be less than that of thread blocking, suspending and waking up operations, which will lead to two context switches of threads!

However, if the lock competition is fierce, or the thread holding the lock needs to occupy the lock for a long time to execute the synchronization block, it is not suitable to use the spin lock, because the spin lock always occupies the cpu for useless work before obtaining the lock, accounting for XX or XX. At the same time, a large number of threads compete for a lock, which will lead to a long time to obtain the lock, The consumption of thread spin is greater than that of thread blocking and pending operation, and other threads that need a cup cannot obtain the cpu, resulting in a waste of cpu. So in this case, we have to turn off the spin lock;

[](

)Synchronized synchronization lock

synchronized, which can treat any non NULL object as a lock. It is an exclusive pessimistic lock and a reentrant lock.

[](

)Synchronized scope

White whoring data

  • When acting on a method, it locks the instance of the object (this);

  • When it is used for static methods, the Class instance is locked. This static method lock is equivalent to a global lock of the Class and will lock all threads calling the method

  • When synchronized acts on an object instance, it locks all code blocks that lock the object.

[](

)Lock lock

//Lock lock usually uses reentrant lock ReentrantLock

Lock lock = new ReentrantLock(); 

ReentantLock inherits the interface Lock and implements the methods defined in the interface. It is a reentrant Lock. In addition to completing all the work that synchronized can do, it also provides methods to avoid multi-threaded deadlock, such as responding to interrupt Lock, polling Lock request, timing Lock, etc

public class SaleTicketDemo02 {

    public static void main(String[] args) {

        // Concurrency: multiple threads operate on the same resource class and throw the resource class into the thread

        Ticket2 ticket = new Ticket2();

        // @Functional interface, jdk1 8 lambda expression (parameter) - > {code}

        new Thread(()->{for (int i = 1; i < 40 ; i++)

        ticket.sale();},"A").start();

        new Thread(()->{for (int i = 1; i < 40 ; i++)

        ticket.sale();},"B").start();

        new Thread(()->{for (int i = 1; i < 40 ; i++)

        ticket.sale();},"C").start();

    }

}

// Lock Trilogy

// 1, new ReentrantLock();

// 2, lock.lock(); //  Lock

// 3, finally=> lock. unlock(); //  Unlock

class Ticket2 {

    // Properties and methods

    private int number = 30;

    Lock lock = new ReentrantLock();

    

    public void sale(){

        lock.lock(); // Lock

        try {

            // Business code

            if (number>0){

                System.out.println(Thread.currentThread().getName()+"Sold"+

                (number--)+"ticket,surplus:"+number);

            }

        } catch (Exception e) {

            e.printStackTrace();

        } finally {

            lock.unlock(); // Unlock

        }

    }

} 

[](

)The difference between synchronized and lock locks

  • synchronized is a built-in keyword in java, and lock is a java class

  • synchronized cannot obtain the lock status. Lock can determine whether the lock has been obtained

  • synchronized will automatically release the lock. Lock will not automatically release the lock. You need to release the lock manually. If you don't release the lock, it will cause deadlock

  • synchronized thread 1 (obtains the lock, and then the lock is blocked) and thread 2 (waits, and then waits foolishly), the lock lock does not necessarily wait

  • synchronized reentrant lock, which cannot be interrupted. It is not fair. Lock reentrant lock, which can judge whether the lock is fair or not, can be set by itself

  • synchronized is suitable for a small number of code synchronization problems, and lock is suitable for a large number of code synchronization problems

[](

)Fair lock and unfair lock

Fair lock: very fair: you can come first

Unfair lock: very unfair: you can jump the queue (default)

[](

)Read write lock

White whoring data

In order to improve performance, Java provides read-write locks. Read locks are used where you read and write locks are used where you write. It can be controlled flexibly,

If there is no write lock, the read is non blocking, which improves the execution efficiency of the program to a certain extent.

Read / write locks are divided into read locks and write locks. Multiple read locks are not mutually exclusive. Read locks and write locks are mutually exclusive. This is controlled by the jvm itself. You only need to install the corresponding locks.

Read lock

If your code is read-only data and many people can read it at the same time, but can't write it at the same time, put on the read lock

Write lock

If your code modifies data and only one person is writing and cannot read it at the same time, then write the lock. In short, read the lock when reading, write the lock when writing!

// Locked

class MyCacheLock{

    private volatile Map<String,Object> map = new HashMap<>();

    // Read / write locks: more granular control

    private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();

    private Lock lock = new ReentrantLock();

    // When saving and writing, you only want one thread to write at the same time

    public void put(String key,Object value){

        readWriteLock.writeLock().lock();

        try {

            System.out.println(Thread.currentThread().getName()+"write in"+key);

            map.put(key,value);

            System.out.println(Thread.currentThread().getName()+"write in OK");

        } catch (Exception e) {

            e.printStackTrace();

        } finally {

            readWriteLock.writeLock().unlock();

        }

    }

    // Take, read, everyone can read!

    public void get(String key){

        readWriteLock.readLock().lock();

        try {

            System.out.println(Thread.currentThread().getName()+"read"+key);

            Object o = map.get(key);

            System.out.println(Thread.currentThread().getName()+"read OK");

        } catch (Exception e) {

            e.printStackTrace();

        } finally {

            readWriteLock.readLock().unlock();

        }

    }

} 

White whoring data

[](

)Lock optimization

Reduce lock holding time

Only lock programs with thread safety requirements

Reduce lock granularity

Split a large object (which may be accessed by many threads) into small objects, which greatly increases the degree of parallelism and reduces lock competition.

Lock separation

The most common lock separation is ReadWriteLock, which is divided into read lock and write lock according to the function. In this way, reading is not mutually exclusive, reading and writing are mutually exclusive, which not only ensures thread safety, but also improves performance,

Lock coarsening

Each thread is required to hold the lock as short as possible, that is, the lock should be released immediately after using the public resources.

However, everything has a degree. If the same lock is constantly requested, synchronized and released, it will consume valuable resources of the system, which is not conducive to performance optimization

Lock elimination

If you find objects that cannot be shared, you can eliminate the lock operation of these objects

deadlock

A deadlock occurs when two or more threads are waiting for each other to complete execution before proceeding. The result is that these threads are trapped in infinite waiting.

How to avoid thread deadlock?

Just break one of the four conditions that cause deadlock.

White whoring data

  • Destroy mutually exclusive condition: we can't destroy this condition, because we use locks to make them mutually exclusive (critical resources need mutually exclusive access).

  • Destruction request and retention conditions: apply for all resources at one time.

  • Destroy the condition of no deprivation: when a thread occupying some resources further applies for other resources, if it fails to apply, it can actively release the resources it occupies.

  • Breaking the cycle waiting condition: prevent by applying for resources in order. Apply for resources in a certain order, and release resources in reverse order

[](

)Thread basic method

Thread related basic methods include wait, notify, notifyAll, sleep, join, yield, etc.

[](

)Thread wait

The thread calling this method enters the WAITING state. It will return only after WAITING for the notification of another thread or being interrupted. It should be noted that after calling the wait() method, the lock of the object will be released.

[](

)Thread sleep

Sleep causes the current thread to sleep. Unlike the wait method, sleep does not release the lock currently held. sleep(long) causes the thread to enter the timed-waiting state, while the wait() method causes the current thread to enter the waiting state

[](

)Thread yield

yield will cause the current thread to give up the CPU execution time slice and compete for the CPU time slice again with other threads. In general, threads with high priority are more likely to successfully compete for CPU time slices

[](

)Thread interrupt

White whoring data

Interrupting a thread is intended to give the thread a notification signal, which will affect an interrupt identification bit inside the thread. The thread itself does not change state

[](

)Join waits for other threads to terminate

When a thread's join() method is invoked in the current thread, the current thread becomes blocked until the end of another thread, and the current thread is changed from blocking state to ready state, waiting for cpu's favor.

last

CodeChina open source project: [analysis of Java interview questions of front-line large manufacturers + core summary learning notes + latest explanation Video]

Java architecture advanced interview and knowledge point document notes

This document has 498 pages in total, including interview analysis and knowledge points sorting of Java collection, concurrent programming, JVM, Dubbo,Redis, Spring, MySQL, Kafka, etc

Java distributed advanced interview question parsing document

All of them include distributed interview question analysis, including distributed message queue, Redis cache, sub database and sub table, micro service architecture, distributed high availability, read-write separation, etc!

Analysis of necessary questions and document learning notes for Internet Java programmer interview

Java architecture advanced video analysis collection
Unlike the wait method, sleep does not release the lock currently held. sleep(long) will cause the thread to enter the timed-waiting state, while the wait() method will cause the current thread to enter the waiting state

[](

)Thread yield

yield will cause the current thread to give up the CPU execution time slice and compete for the CPU time slice again with other threads. In general, threads with high priority are more likely to successfully compete for CPU time slices

[](

)Thread interrupt

White whoring data

Interrupting a thread is intended to give the thread a notification signal, which will affect an interrupt identification bit inside the thread. The thread itself does not change state

[](

)Join waits for other threads to terminate

When a thread's join() method is invoked in the current thread, the current thread becomes blocked until the end of another thread, and the current thread is changed from blocking state to ready state, waiting for cpu's favor.

last

CodeChina open source project: [analysis of Java interview questions of front-line large manufacturers + core summary learning notes + latest explanation Video]

Java architecture advanced interview and knowledge point document notes

This document has 498 pages in total, including interview analysis and knowledge points sorting of Java collection, concurrent programming, JVM, Dubbo,Redis, Spring, MySQL, Kafka, etc

[external chain picture transferring... (img-QSD92rv9-1630719958408)]

Java distributed advanced interview question parsing document

All of them include distributed interview question analysis, including distributed message queue, Redis cache, sub database and sub table, micro service architecture, distributed high availability, read-write separation, etc!

[external chain picture transferring... (img-hiMT9yjC-1630719958409)]

Analysis of necessary questions and document learning notes for Internet Java programmer interview

[external chain picture transferring... (img-aLDZF00x-1630719958411)]

Java architecture advanced video analysis collection

Keywords: Java Back-end Interview Programmer

Added by shwathi on Fri, 17 Dec 2021 02:53:10 +0200