Interview must communicate between multiple threads

1. What is communication between multiple threads?

        Communication between multiple threads is actually multiple threads operating on the same resource, but the actions are different.

2. Communication requirements between multiple threads

        Requirements: The first thread writes (input) the user, and the other thread fetches the read (out) user to implement the operation of writing one and reading one.

                        

The code demo is as follows:

Shared resource entity class

class Res {
    public String userSex;
    public String userName;
}

Input thread resources

class InpThread extends Thread {
	private Res res;

	public InpThrad(Res res) {
            this.res = res;
	}

	@Override
	public void run() {
            int count = 0;
            while (true) {
		if (count == 0) {
		    res.userName = "小明";
		    res.userSex = "男";
		} else {
		    res.userName = "小红";
		    res.userSex = "女";
		}
		count = (count + 1) % 2;
	    }
	}
}

Output thread

class OutThread extends Thread {
	private Res res;

	public OutThread(Res res) {
	    this.res = res;
	}

	@Override
	public void run() {
            while (true) {
                System.out.println(res.userName + "--" + res.userSex);
	      }
	}
}

Run the code

public static void main(String[] args) {
        Res res = new Res();
	InpThrad inpThrad = new InpThrad(res);
	OutThread outThread = new OutThread(res);
	intThrad.start();
	outThread.start();
}

operation result

      

Note: At this time, the data will be disordered, causing thread safety problems

So what will be the result of running the thread safety problem?

In the input thread Inp Thr E AD category plus synchronized

class InpThread extends Thread {
	private Res res;

	public InpThrad(Res res) {
		this.res = res;
	}

	@Override
	public void run() {
            int count = 0;
	    while (true) {
		synchronized (res) {
		if (count == 0) {
		    res.userName = "小明";
		    res.userSex = "男";
		} else {
		    res.userName = "小红";
		    res.userSex = "女";
		}
		count = (count + 1) % 2;
	        }
	    }
        }
}

In the output thread OutThread class also add synchronized

class OutThread extends Thread {
	private Res res;

	public OutThread(Res res) {
		this.res = res;
	}

	@Override
	public void run() {
            while (true) {
	        synchronized (res) {
		    System.out.println(res.userName + "--" + res.userSex);
		}
	    }
	}
}

So what is the result of the operation at this time?

     

Note: Two threads, In p Thr ead and OutThread, are executed in parallel at the same time. When the OutThread thread acquires the CPU, it will print multiple times, and it will not achieve the effect of sequential printing.

So how can we achieve this effect in sequence?

3、wait()、notify()、notifyAll()方法

wait (), notify (), notifyAll () are three methods defined in the Object class, which can be used to control the state of the thread.

  • If the object is called a thread wait method will cause the object to hold control of the object to pay out, then in a wait state.
  • If the object called notify method will notify a thread is waiting for control of the object can continue to continue running.
  • If the object calls the notifyAll method, it will notify all threads waiting for control of the object to continue running.

Using these three methods can achieve synchronization between threads, and achieve the effect of writing one reading one.

Code demo

Shared resource entity class

class Res {
	public String userSex;
	public String userName;
	//线程通讯标识
	public boolean flag = false;
}

Input thread

class InpThrad extends Thread {
	private Res res;

	public InpThrad(Res res) {
		this.res = res;
	}

	@Override
	public void run() {
            int count = 0;
            while (true) {
	        synchronized (res) {
		if (res.flag) {
		    try {
			// 当前线程变为等待,但是可以释放锁
		        res.wait();
		    } catch (Exception e) {
                        // TODO: handle exception
		    }
		  }
		if (count == 0) {
		    res.userName = "小明";
		    res.userSex = "男";
		} else {
		    res.userName = "小红";
		    res.userSex = "女";
		}
		count = (count + 1) % 2;
		res.flag = true;
		// 唤醒其他等待线程
		res.notify();
		}
	    }
	}
}

Output thread

class OutThread extends Thread {
	private Res res;

	public OutThread(Res res) {
	    this.res = res;
	}

	@Override
	public void run() {
	    while (true) {
	        synchronized (res) {
	        if (!res.flag) {
		    try {
                        res.wait();
		    } catch (Exception e) {
		        // TODO: handle exception
                    }
		}

		System.out.println(res.userName + "--" + res.userSex);
		res.flag = false;
		res.notify();
		}
	    }
        }
}

operation result

       

At this time, the synchronization between the threads achieves the effect of writing one and reading one.

4. What is the difference between wait and sleep?

  • For the sleep () method, we must first know that the method belongs to the Thread class , and the wait () method belongs to the Object class.
  • sleep () method results in a program to suspend the specified time, so that the cpu to other threads, but it 's monitoring the state remains the , when the specified time is up will automatically resume operation.
  • wait is used to synchronize between multiple threads (used with synchronized)
  • During the sleep () method call, the thread does not release the object lock. When the wait () method is called, the thread will release the object lock and enter the waiting lock pool waiting for this object. Only after this object calls the notify () method, the thread will enter the object lock pool to prepare .

5. Why are wait and notify defined in the object class?

Because we are using multiple threads for synchronization, the lock is defined by ourselves. In order to allow all classes to be used, wait and notify are defined in the object class.

6. Lock

After jdk1.5, the Lock interface (and related implementation classes) was added to the concurrent package to implement the lock function. The Lock interface provides a synchronization function similar to the synchronized keyword, but it needs to manually acquire and release the lock when using it. .

How to write Lock

Lock lock  = new ReentrantLock();
lock.lock();
try{
    //可能会出现线程安全的操作
}finally{
    //一定要在finally中释放锁
    lock.unlock();
}

The difference between the Lock interface and the synchronized keyword

  • Lock interface can be non-blocking attempt to acquire a lock  for the current thread tries to acquire the lock if the lock is not the time to get other threads, then successfully acquire and hold the lock.
  • The Lock interface can be interrupted to acquire the lock differently from synchronized. The thread that acquired the lock can respond to the interrupt. When the thread that acquired the lock is interrupted, an interrupt exception will be thrown and the lock will be released.
  • The Lock interface acquires the lock before the specified deadline. If the deadline still expires and the lock cannot be acquired, return.

 Condition usage

 The function of Condition is similar to the function of wait () and notify () in traditional threading technology

Condition condition = lock.newCondition();
res.condition.await();  //类似于wait
res.condition.signal(); //类似于notify

Using Lock can also achieve the above effect, the code demonstration is as follows:

Shared entity resource class

class Res {
	public String userSex;
	public String userName;
	// flag=false时out线程未读取值
	public boolean flag = false;
	// 定义一个锁
	Lock lock = new ReentrantLock();
	Condition condition = lock.newCondition();
}

 Input thread

class InpThread extends Thread {
	private Res res;

	public InpThread(Res res) {
		this.res = res;
	}
	@Override
	public void run() {
            int count = 0;
            while (true) {
		try {
		    res.lock.lock();
		    if (res.flag) {
			try {
			    // 当前线程变为等待,但是可以释放锁
			    // 类似于res.wait();
			    res.condition.await();
			} catch (Exception e) {

			}
		      }

		    if (count == 0) {
			    res.userName = "小明";
			    res.userSex = "男";
			} else {
			    res.userName = "小红";
			    res.userSex = "女";
			}

		    count = (count + 1) % 2;
		    res.flag = true;
		    // 唤醒当前线程 // 类似于res.notify();
		    res.condition.signal();
		} catch (Exception e) {
		    // TODO: handle exception
		} finally {
		    res.lock.unlock(); //释放锁,一定要在finally中
		}
	    }
	}
}

Output thread

class OutThread extends Thread {
	private Res res;

	public OutThread(Res res) {
		this.res = res;
	}

	@Override
	public void run() {
            while (true) {
		try {
		res.lock.lock();
		if (!res.flag) {
		    try {
		        res.condition.await();
		    } catch (Exception e) {
		        // TODO: handle exception
		    }
		}

		System.out.println(res.userName+"--"+res.userSex);
		res.flag = false;
		res.condition.signal();
	    } catch (Exception e) {

            } finally {
		res.lock.unlock();  //释放锁,一定要在finally中
            }
	}
    }
}

operation result

       

So using Lock can also achieve the above effect.

Published 19 original articles · praised 279 · 80,000 views

Guess you like

Origin blog.csdn.net/Mr_wxc/article/details/105660052