Java multi-threaded interview knowledge Lite

table of Contents

 

Multithreading

Thread of the life cycle

Q: how do you understand multithreading

Inter-thread communication

lock

volatile

ThreadLocal

Thread Pool

And contracting tools

Programming problem


Multithreading

Thread of the life cycle

New - Ready - running - blocked - ready - run - Death

 

 

Q: how do you understand multithreading

  1. Definition: Multithreading refers to achieve concurrent execution of multiple threads technology from the software or hardware. A computer with multi-threading capability due to hardware support and can execute more than one thread at the same time, thereby enhancing the overall processing performance.
  2. The reason exists: because of the low single-threaded processing capabilities. Analogy, a man few people Quban Quban brick and brick, while a person can only move a car, but few people can move simultaneously with multiple vehicles.
  3. Implementation: How to implement threads, Thread, Runnable, Callable in Java.
  4. Question: thread can achieve greater throughput, however great the cost, time, size of thread stack space required to switch threads, use the thread pool so repeated use, when it is finished using the thread back into the thread pool, to avoid creating and overhead destruction.

Inter-thread communication

  1. Wait for notification mechanism wait (), notify (), join (), interrupted ()
  2. Concurrent tool synchronized, lock, CountDownLatch, CyclicBarrier, Semaphore

lock

What is the lock

Lock is assigned a different way in the case of threads executing different threads compete for resources down synchronous control tool, and only after obtaining thread synchronization code to access the lock, or wait for the end of the other threads release the lock

synchronized

Usually wait, notify, notifyAll one use.
wait: the possession of the object lock is released, the release of CPU, into the waiting queue can only continue the thread through notify / all.
sleep: it is the release of CPU, but does not release possession of the object lock automatically continue after the end of the thread sleep.
notify: wake up a thread waiting in the queue, so get a lock for a visit.
notifyAll: wake up all the threads waiting in the queue waiting for this lock, let the competition to get a lock.

lock

Has the same semantics synchronize, but add some other features, such as interrupt lock waiting and waiting time lock, so the lock can be used instead of synchronize, but must be manually locked the lock is released

The difference between the two

  • Performance: Under intense resource competition, lock performance will be better than synchronized; if not fierce competition for resources, performance of the two is about the same
  • Usage: synchronized block of code can be used, the methods. lock by code implementation, there is a more precise semantics of threads, but the need to manually release also provides a variety of synchronization, such as fair locks, there is a time limit of synchronization, synchronization can be interrupted
  • Principle: synchronized at the JVM level to achieve, and will add monitorenter monitorexit bytecode generated, any object has associated with it a monitor, and a monitor after being held, he will be locked. monitor the JVM is a synchronization tool, synchronized to ensure the visibility of further variables shared by the memory barrier command. lock code level achieved in the use AQS, were blocked by Unsafe.park call to the operating system kernel
  • Function: for example, more powerful ReentrantLock
    1. ReentrantLock can specify whether fair or unfair lock lock, but only non-synchronized fair locks, the so-called fair lock is to wait for the thread to acquire the lock
    2. ReentrantLock provides a Condition (condition) class that implements thread are grouped need to wake up wake up, not like synchronized or random wake up a thread or threads all wake up
    3. ReentrantLock provides a mechanism capable of interrupting the thread waiting for the lock, this mechanism is implemented by lock.lockInterruptibly ()

When we write synchronization, priority synchronized, if you have special needs, and then further optimized. Atomic ReentrantLock and if used improperly, not only does not improve performance, but also may lead to disaster.

The type of lock

  • Lock fair / unfair Lock

Fair locking means in order to apply a plurality of threads to acquire a lock latch
ReentrantLock the constructor specifies whether the lock latch is fair, fair non-default lock. Synchronized is a non-lock fair

  • Reentrant lock

Refers to the same thread acquires the lock when the outer layer of the method, the method will automatically get into the inner lock
ReentrantLock, his name can be seen be a reentrant lock, whose name is Re entrant Lock re-enter the lock
Synchronized, also a reentrant lock. One of the benefits can be reentrant lock is to a certain extent to avoid deadlock

  • Exclusive lock / shared lock

Exclusive lock means the lock can only be held by a thread. Shared lock means the lock can be held by multiple threads
ReentrantLock is the exclusive lock. But for another implementation class ReadWriteLock Lock, which lock is a shared read lock which locks the exclusive write lock is
a shared read lock lock can ensure very efficient concurrent read, read, write, read, write processes are mutually exclusion of
Synchronized is the exclusive lock

  • Lock optimistic / pessimistic locking

Pessimistic locking in Java using a variety of locks is
optimistic locking used in Java, the algorithm is CAS, a typical example is based atoms, atomic operations achieved by spin CAS updates

  • Biased locking / lock lightweight / heavyweight lock

For lock status Synchronized: the
biased locking is to reduce the non-competition and only one thread in the case of the use of locks, locks produced using the lightweight performance of consumption. Refers to the period of synchronization code has been accessed by a thread, in the absence of competition in the entire synchronization are eliminated
lightweight lock is to reduce the absence of real competition, the use produces heavyweight lock performance overhead. When the lock is biased locking finger when being accessed by another thread, it will be upgraded to lightweight biased locking lock, another thread tries to acquire a lock in the form of CAS spin, does not block
heavyweight lock means that when the lock as a lightweight lock when another thread though is the spin, but spin will not last forever, when the spin a certain number of times, has not yet acquired lock, will enter the blocking, the lock inflation heavyweight lock

  • Spinlock / adaptive spinlock

Refers to a thread attempts to acquire the lock will not be blocked immediately, instead of using a circular fashion to try to acquire the lock, this benefit is to reduce the consumption of thread context switching, the drawback is that the cycle will consume CPU, the default number is 10 spin
adaptive spin spin lock is no longer a fixed number of times, but once in a locked state with spin lock time and the owner of the decision by the former, is a predictor virtual machine lock status

volatile

Features:

  1. Working memory and the main memory, the main memory is generated directly interact, read and write operations, to ensure visibility;
  2. Prohibiting the JVM instruction reordering.

ThreadLocal

Use ThreadLocal<UserInfo> userInfo = new ThreadLocal<UserInfo>()way, so that each will maintain an internal thread ThreadLocalMap, inside contains a number of Entry (KV key-value pairs), each will first get access to the current thread ID, and then get the thread object Map, then the Map interaction.

Thread Pool

origin

new Thread drawbacks:

  • Each time you start a new thread requires new Thread object thread, poor performance. Threads in the thread pool can be reused, reducing object creation, recovery of overhead.
  • Thread the lack of unified management, you can limit the new thread, resulting OOM. You can control the thread pool can create the maximum number of concurrent threads of execution.
  • Lack of engineering practice some advanced features such as periodic execution thread interrupts. Thread pool provided a regular basis, the number of concurrent control

When the core thread pool parameters

  • corePoolSize: the number of core number of threads, thread pool threads should be permanent
  • maximumPoolSize: The maximum number of threads in the thread pool allows the non-core thread after the timeout will be cleared
  • workQueue: blocking queue of tasks waiting to be executed is stored
  • keepAliveTime: Thread does not have time to perform tasks that can be held
  • unit: unit of time
  • threadFactory: thread factory, to create a thread
  • rejectHandler: when the policy of denial when submitting tasks (throwing an exception, mission thread with the caller is located, discarding the first task execution of the current task queue, discards the task)

Create a logical thread

The following tasks commit logic from ThreadPoolExecutor.execute method:

  1. If the number of threads running <corePoolSize, directly create a new thread, even if there are other threads are idle
  2. If the number of threads running> = corePoolSize
    2.1 is inserted into the queue if successful, the completion of this task submitted, but does not create a new thread
    2.2 If you insert a queue fails, the queue is full
    2.2.1 If the current count <maximumPoolSize, thread creates a new thread into the thread pool
    2.2.2 If the current number of threads> = maximumPoolSize, will refuse to perform the specified policy

Blocking queue strategy

  • Direct submission. SynchronousQueue is not a data buffer BlockingQueue, insert put its producer thread must wait for the consumer to remove the operation take. The task submitted directly to the thread instead of keeping them.
  • Unbounded queue. When using unlimited maximumPoolSizes, it will lead to a new job waiting in the queue when all corePoolSize threads are busy.
  • Bounded queue. When using a limited maximumPoolSizes, bounded queue (such as ArrayBlockingQueue) helps prevent resource exhaustion, but may be difficult to adjust and control.

And contracting tools

CountDownLatch

Atresia is a counter can block the main thread, so other threads thread synchronization tools to meet the main thread under certain conditions, to continue to perform.

 

图中,A为主线程,A首先设置计数器的数到AQS的state中,当调用await方法之后,A线程阻塞,随后每次其他线程调用countDown的时候,将state减1,直到计数器为0的时候,A线程继续执行。

使用场景:
并行计算:把任务分配给不同线程之后需要等待所有线程计算完成之后主线程才能汇总得到最终结果
模拟并发:可以作为并发次数的统计变量,当任意多个线程执行完成并发任务之后统计一次即可

Semaphore

信号量是一个能阻塞线程且能控制统一时间请求的并发量的工具。比如能保证同时执行的线程最多200个,模拟出稳定的并发量。

public class CountDownLatchTest {

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newCachedThreadPool();
        Semaphore semaphore = new Semaphore(3); //配置只能发布3个运行许可证
        for (int i = 0; i < 100; i++) {
            int finalI = i;
            executorService.execute(() -> {
                try {
                    semaphore.acquire(3); //获取3个运行许可,如果获取不到会一直等待,使用tryAcquire则不会等待
                    Thread.sleep(1000);
                    System.out.println(finalI);
                    semaphore.release(3);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }
        executorService.shutdown();
    }
}

由于同时获取3个许可,所以即使开启了100个线程,但是每秒只能执行一个任务

使用场景:
数据库连接并发数,如果超过并发数,等待(acqiure)或者抛出异常(tryAcquire)

CyclicBarrier

可以让一组线程相互等待,当每个线程都准备好之后,所有线程才继续执行的工具类

 

 

与CountDownLatch类似,都是通过计数器实现的,当某个线程调用await之后,计数器减1,当计数器大于0时将等待的线程包装成AQS的Node放入等待队列中,当计数器为0时将等待队列中的Node拿出来执行。

与CountDownLatch的区别:

  1. CountDownLatch是一个线程等其他线程,CyclicBarrier是多个线程相互等待
  2. CyclicBarrier的计数器能重复使用,调用多次

使用场景: 有四个游戏玩家玩游戏,游戏有三个关卡,每个关卡必须要所有玩家都到达后才能允许通过。其实这个场景里的玩家中如果有玩家A先到了关卡1,他必须等到其他所有玩家都到达关卡1时才能通过,也就是说线程之间需要相互等待。

编程题

交替打印奇偶数

public class PrintOddAndEvenShu {
    private int value = 0;

    private synchronized void printOdd() {
        while (value <= 100) {
            if (value % 2 == 1) {
                System.out.println(Thread.currentThread() + ": -" + value++);
                this.notify();
            } else {
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        }

    }

    private synchronized void printEven() {
        while (value <= 100) {
            if (value % 2 == 0) {
                System.out.println(Thread.currentThread() + ": --" + value++);
                this.notify();
            } else {
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        PrintOddAndEvenShu print = new PrintOddAndEvenShu();
        Thread t1 = new Thread(print::printOdd);
        Thread t2 = new Thread(print::printEven);
        t1.start();
        t2.start();
        t1.join();
        t2.join();
    }
}

 

发布了142 篇原创文章 · 获赞 31 · 访问量 2万+

Guess you like

Origin blog.csdn.net/qq_38905818/article/details/103803411