The vast sea of millions, thank you for this second you see here. I hope my series of interview questions can help you! ‘!

May you keep your love and go to the mountains and seas in the coming days!

Three interview questions a day, achievement better self

Let’s continue talking about multithreading today.

1. Do you know about thread safety?

Thread safety problem: In multi-threaded mode, when multiple threads operate on the same shared data, the first thread does not have time to update the shared data. As a result, another thread does not get the latest data and updates the data, resulting in thread safety problems. A more common scenario is buying tickets.

Let me give you an example:

Demand: Buying tickets for Jay Chou’s concert, for example, there are three Windows selling 100 tickets at the same time. A window is a thread object, and with 100 tickets, you have multiple threads competing for CPU resources to use the right tickets.

Heh heh, I went to MyGirl when I was in college, but I can’t do it now. Without further ado, let’s look at the code:

public class SellTicketDemo {
    public static void main(String[] args) {
        // Create a thread task object
        Ticket ticket = new Ticket();
        // Create three window objects
        Thread thread = new Thread(ticket, "Window 1");
        Thread thread2 = new Thread(ticket, "Window 2");
        Thread thread3 = new Thread(ticket, "Window 3");

        // Sell tickets at the same timethread.start(); thread2.start(); thread3.start(); }}// Create Ticket to implement Runnale
class Ticket implements Runnable {

    private int ticket = 100; // 100 tickets for Jay Chou's concert

    // execute the logic of buying tickets
    @Override
    public void run(a) {
        // Note that each window has the right to sell tickets
        while (true) {
            if (ticket > 0) { // There are tickets available
                // Ticket issue: because come in to buy a ticket, always have a ticket, always slowly run out of tickets
                try {
                    // Use sleep to simulate ticket issuing time.
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                Get the name of the current thread object
                System.out.println(Thread.currentThread().getName() + "For sale :"+ ticket--); }}}}Copy the code

We created Ticket to implement the Runnable interface, rewrote the run method to implement the Ticket function, and defined a shared variable. And create three threads in the main method to achieve the function of three Windows to buy tickets. Finally, let’s look at the results:

After you run it a few more times, you can see something like this:

  1. Selling tickets that do not exist, such as zero and -1, does not exist. And that’s not allowed to happen. Who sells zero tickets or even minus one?
  2. The same number of tickets appear to be sold, such as 8 and 1 tickets are sold three times. That’s outrageous. One ticket can sell three people haha.

The occurrence of these problems means that we are not thread safe. So what exactly are thread safety issues? We can conclude that:

Is caused by global variables and static variables. If there are only reads and no writes on a global variable or static variable per thread, the global variable is generally thread-safe. If you have multiple threads performing write operations at the same time, you generally need to consider thread synchronization, otherwise it may affect thread safety.

The conditions under which a thread-safety issue can occur:

  1. Whether multi-threaded environment, single thread to operate on data, of course, there is no problem drop!
  2. Is there a shared variable? In the code above, concert tickets are defined with a global variable ticket, which is shared by multiple threads.
  3. If there are multiple statements that share data, in the code above, after you sell a ticket, the ticket variable must be decrement, so the ticket is decrement.

Good ah! Let’s keep going

2. So how do you solve the thread safety problem?

We can address thread-safety issues by introducing thread synchronization. In the above ticket selling problem, the security problem of multiple threads accessing a resource concurrently: that is, to solve the problem of duplicate tickets and non-existent tickets, Java provides synchronization mechanism to solve.

The specific solution is as follows:

  1. When the thread of window 1 enters the ticket buying process, the thread of window 2 and window 3 can only wait outside. At this time, the operation of ticket buying cannot be carried out. They can only wait for the completion of ticket buying in window 1 and then enter window 1, Window 2 and window 3 to seize CPU resources again to perform the ticket selling function.
  2. In other words, when a thread modifies a shared resource, other threads cannot modify the resource. Only after the modification is complete and synchronization is completed, can they grab CPU resources and complete corresponding operations. This ensures data synchronization and solves the problem of thread insecurity.

The synchronized keyword gives us several methods:

  1. Implementing synchronized code blocks:synchronizedThe keyword can be used in a block of a method to indicate that only resources in that block are mutually exclusive.
  2. Implement synchronization method: usesynchronizedA modified method, called a synchronous method, ensures that while one thread executes the method, other threads have to wait outside the method.
public class SynchronizedDemo {

    // The method is actually locked on this
    private synchronized void synchronizedTest(a) {}The lock object can be arbitrary. You can use this, a.class object, or any object
    private void synchronizedTest2(a){
        synchronized (this) {}}// Add a lock to a static method
    private synchronized static void synchronizedTest3(a) {}}Copy the code

In addition to the synchronized keyword, there is also a Lock, and this method needs to define the Lock release location.

Lock lock = new ReentrantLock();

lock.lock(); // Define your own lock opening position

try {
    System. out. println("We got the lock.");
} catch (Exception e) {
} finally {
    System. out. println("We released the lock.");
    
    lock.unlock();// You need to define your own lock release location, otherwise there will be deadlock problems.
}
Copy the code

So let’s summarize:

How do we ensure safety?

  1. Use the synchronized keyword to implement synchronized code blocks or methods. Until one thread can operate on a resource, the other threads must wait.
  2. With manual Lock Lock, Lock position can be relatively flexible, but there must be a Lock release action.

The difference between the two:

  1. Synchronized is a Java keyword, and Lock is a class, which is an interface. We typically use ReentrantLock to create instance objects.
  2. Synchronized can be modified in classes, methods, variables, and can achieve synchronized code blocks, while ReentrantLock only applies to code block locks.
  3. Synchronized would normally operate on the Mark Word object header, whereas ReentrantLock’s underlying call is the Unsafe Park method.
  4. ReentrantLock must manually acquire and release locks, whereas synchronized does not.
  5. Both are reentrant locks. Reentrant locks allow the same thread to acquire the same lock multiple times. If a thread has acquired a lock, it can acquire it again without deadlock. If it is a non-lockable reentrant, it will cause a deadlock.

Now, speaking of deadlocks, one last question for you:

3. Why don’t you tell me what a deadlock is?

A deadlock is a phenomenon in which two or more processes (threads) are blocked during execution, either by competing for resources or by communicating with each other, and cannot proceed without external action. The system is said to be in a deadlock state or the system has a deadlock. These processes (threads) that are always waiting for each other are called deadlocked processes (threads).

Take an example: you and your girlfriend quarrel, you begin to choke each other hair, you clench her show long hair, and she clench your hair, you two pain than, but each other are violent temper, each other ruthlessly say you don’t put, don’t put I also don’t put, see first pain dead! While you’re looking at each other, you’re vowing not to let go. Now it’s pretty much deadlocks, waiting for each other.

Let’s briefly demonstrate the code for thread deadlocks:

public class DeadlockDemo {
    public static void main(String[] args) {
        MyRunnable myRunnable = new MyRunnable();

        new Thread(myRunnable, "Theatergoer 1 see").start();
        new Thread(myRunnable, "Theatergoer 2 see").start(); }}class MyRunnable implements Runnable {
    Object me = new Object();
    Object myGirl = new Object();

    @Override
    public void run(a) {
        synchronized (me) {
            System.out.println(Thread.currentThread().getName() + "Me: I'll strangle you! Are you going to let it go?");

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

            System.out.println(Thread.currentThread().getName() + "Me: If you let go, I'll let go!");
            synchronized (myGirl) {
                System.out.println(Thread.currentThread().getName() + "Me: Let go! Aren't you in pain?"); }}synchronized (myGirl) {
            System.out.println(Thread.currentThread().getName() + "MyGirl: I'm gonna choke you! Are you still holding on? You who floor tonight!");

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

            System.out.println(Thread.currentThread().getName() + "MyGirl: You're the one to let go!");
            synchronized (me) {// t1, objB, can't get lock A, wait
                System.out.println(Thread.currentThread().getName() + "MyGirl: Looks like you're sleeping on the floor tonight."); }}}}Copy the code

First look at the results:

We can see that the process is still running, but the code is not running.

Thread 1 is waiting for me to let go of the second synchronized (myGirl) block when thread 2 enters and locks the first synchronized (me) block.

When thread 1 wants to enter the second synchronized (me), it finds that the lock of the ME is taken and falls into the waiting state. When thread 2 finds that it wants to enter the first synchronized (myGirl), myGirl is seized by thread 1 and falls into the waiting state. At this point, two people are waiting for each other to finish releasing the lock, and they are stuck in an infinite waiting state.

The necessary conditions for deadlock are:

Two or more threads are in a state of waiting for each other due to competing for resources during execution.

  1. Mutually exclusive: Threads are exclusive to allocated resources, that is, a resource can only be occupied by one thread until it is released by that thread (process).
  2. Request and hold condition: when a thread is blocked due to a resource occupied by a request, it will hold on to the acquired resource, that is, a thread has already qualified for a resource, and then makes a new resource request.
  3. Non-deprivation condition: a thread cannot forcibly deprivate a resource it has acquired before using it up. The resource can be released only after the thread uses it up.
  4. Circular wait condition: When a deadlock occurs, the waiting thread must form a loop chain of resources (similar to an infinite loop), causing a permanent block.

Nice guy! Today is over here, looking forward to your arrival tomorrow, I hope to continue to keep a surprise!

Note: If there are any mistakes and suggestions, please leave a message! If this article is helpful to you, I hope you will pay attention to it for three times. Thank you very much! You can also search the wechat prince Nezha public number private chat me, thank you guys!