About Thread Communication Questions (Interview Questions)

About volitele, notify, wait interview questions:

 

1. Question: When two threads operate an object, one of the threads should not keep waiting for the other thread in an infinite loop

      Solution: In the above situation, if the volatile keyword is not added, a thread will wait in a loop

  

(1) Code example:

package net.oschina.tkj.mulitcoding.notifykey;

import java.util.ArrayList;
import java.util.List;

/**
 * notify, wait wait: make the thread wait and release the thread's lock notify: wake up a thread, but do not release the lock, so the problem of thread information synchronization may occur
 * notify and wait are both methods of changing thread state, so they should be placed in synchronizd
 *
 * 1. The following problem: When two threads operate an object, one of the threads should not keep waiting for the other thread in an infinite loop
 *
 * In the above case, if the volatile keyword is not added, a thread will wait in a loop
 *
 *
 * @author Freedom
 *
 */
public class NotifyWaitV1 {

	private static volatile List<String> list = new ArrayList<>();

	public void add() {
		list.add("freedom");
	}

	public int size() {
		return list.size();
	}

	// start two threads
	public static void main(String[] args) {

		final NotifyWaitV1 v1 = new NotifyWaitV1();

		Thread t1 = new Thread(new Runnable() {

			@Override
			public void run() {

				try {
					for (int i = 0; i < 10; i++) {
						v1.add();
						System.out.println("Current thread:"
								+ Thread.currentThread().getName() + "Added an element!");

						Thread.sleep(100);
					}
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace ();
				}
			}
		}, "t1");

		Thread t2 = new Thread(new Runnable() {

			@Override
			public void run() {

				while (true) {
					if (v1.size() == 5) {
						System.out.println("Current thread:"
								+ Thread.currentThread().getName()
								+ "list.size==5 to exit the loop, the task is completed!");
						throw new RuntimeException();
					}
				}
			}
		}, "t2");

		t2.start();
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace ();
		}

		t1.start();

	}

(2) Result display:

①Do not add the "volatile" keyword



 

②Add volatile keyword



 

 

2. Solved with volatile, the problem of empty waiting for a thread However, the while loop wastes performance. Is there a mechanism to solve this problem?

      Solution: At this point, the notify and wait mechanisms can be used to obtain the result from the execution result. Notify wakes up a thread, but does not release the lock. In the example, the content of the t2 thread will only be executed after the execution of the t1 thread is completed.

 

(1) Code example

package net.oschina.tkj.mulitcoding.notifykey;

import java.util.ArrayList;
import java.util.List;

/**
 * notify, wait wait: make the thread wait and release the thread's lock notify: wake up a thread, but do not release the lock, so the problem of thread information synchronization may occur
 * notify and wait are both methods of changing thread state, so they should be placed in synchronizd
 *
 * 1. The following problem: When two threads operate an object, one of the threads should not keep waiting for the other thread in an infinite loop
 *
 * In the above case, if the volatile keyword is not added, a thread will wait in a loop
 *
 * Problem 2, solved with volatile, the problem of a thread waiting for nothing, but the while loop wastes performance, is there a mechanism to solve this problem?
 *
 * At this time, you can use the notify, wait mechanism to get the result from the execution result, notify wakes up a thread, but does not release the lock,
 * In the example, the content of the t2 thread will be executed only after the execution of the t1 thread ends
 *
 * @author Freedom
 *
 */
public class NotifyWaitV2 {

	private static volatile List<String> list = new ArrayList<>();

	private static final Object lock = new Object();

	public void add() {
		list.add("freedom");
	}

	public int size() {
		return list.size();
	}

	// start two threads
	public static void main(String[] args) {

		final NotifyWaitV2 v1 = new NotifyWaitV2();

		Thread t1 = new Thread(new Runnable() {

			@Override
			public void run() {

				try {

					synchronized (lock) {

						for (int i = 0; i < 10; i++) {
							v1.add();
							System.out.println("Current thread:"
									+ Thread.currentThread().getName()
									+ "Added an element!");

							Thread.sleep(100);
							if (v1.size() == 5) {
								System.out.println("Current thread:"
										+ Thread.currentThread().getName()
										+ "Notify sent!");
								lock.notify();
							}
						}

					}
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace ();
				}
			}
		}, "t1");

		Thread t2 = new Thread(new Runnable() {

			@Override
			public void run() {

				synchronized (lock) {
					if (v1.size() != 5) {
						try {
							lock.wait();
						} catch (InterruptedException e) {
							// TODO Auto-generated catch block
							e.printStackTrace ();
						}

					}
					System.out.println("Current thread:"
							+ Thread.currentThread().getName()
							+ "list.size==5 to exit the loop, the task is completed!");
					throw new RuntimeException();
				}
			}
		}, "t2");

		t2.start();
		try {
			Thread.sleep(3000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace ();
		}

		t1.start();

	}
}

 

(2) Running results:



 

 

3. Question 2 The notify and wait mechanism solves the waste of resources such as loop empty, but if there is a large amount of data in the case of high concurrency, when a business logic node is executed, another thread needs to be awakened to process the data of the current node , the use of notify notification does not solve the problem of real-time communication between threads (notify does not release the thread's lock), so another idea needs to be considered.

 

Solution use: CountDownLatch class object

(1) Code example

package net.oschina.tkj.mulitcoding.notifykey;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;

/**
 * notify, wait wait: make the thread wait and release the thread's lock notify: wake up a thread, but do not release the lock, so the problem of thread information synchronization may occur
 * notify and wait are both methods of changing thread state, so they should be placed in synchronizd
 *
 * ###Question 1### The following question: When two threads operate on an object, make one of them not keep waiting in an infinite loop for the other thread
 *
 * In the above case, if the volatile keyword is not added, a thread will wait in a loop
 *
 * ###Problem 2### Solved with volatile, the problem of a thread waiting for nothing However, the while loop wastes performance, is there a mechanism to solve this problem?
 * At this time, you can use the notify, wait mechanism to get the result from the execution result, notify wakes up a thread, but does not release the lock,
 * In the example, the content of the t2 thread will be executed only after the execution of the t1 thread ends
 *
 * ###Question 3### The notify and wait methods can solve the problem of wasting resources by idling, but they cannot be solved. Therefore, the problem of real-time update of messages between threads needs to be used
 *
 * @author Freedom
 *
 */
public class NotifyWaitV3 {

	private static volatile List<String> list = new ArrayList<>();

	// private static final Object lock = new Object();

	private static final CountDownLatch countDownLatch = new CountDownLatch(1);

	public void add() {
		list.add("freedom");
	}

	public int size() {
		return list.size();
	}

	// start two threads
	public static void main(String[] args) {

		final NotifyWaitV3 v1 = new NotifyWaitV3();

		Thread t1 = new Thread(new Runnable() {

			@Override
			public void run() {

				try {

					// synchronized (lock) {

					for (int i = 0; i < 10; i++) {
						v1.add();
						System.out.println("Current thread:"
								+ Thread.currentThread().getName() + "Added an element!");

						Thread.sleep(100);
						if (v1.size() == 5) {
							System.out.println("Current thread:"
									+ Thread.currentThread().getName()
									+ "A countDown notification was issued!");
							// lock.notify();
							countDownLatch.countDown();
						}
					}

					// }
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace ();
				}
			}
		}, "t1");

		Thread t2 = new Thread(new Runnable() {

			@Override
			public void run() {

				// synchronized (lock) {
				if (v1.size() != 5) {
					try {
						// lock.wait();
						countDownLatch.await();// t2 thread waiting
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace ();
					}

				}
				System.out.println("Current thread: " + Thread.currentThread().getName()
						+ "list.size==5 to exit the loop, the task is completed!");
				throw new RuntimeException();
			}
			// }
		}, "t2");

		t2.start();
		try {
			Thread.sleep(300);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace ();
		}

		t1.start();

	}
}

 (2) Running results:



 

 

4. Summary

(1) volatile, which can solve the visibility when multiple threads share data, but cannot guarantee atomic operations;

(2) wait makes the thread in a waiting state and releases the thread's lock;

(3) notify wakes up a thread, but will hold the thread's lock;

(4) sleep makes the thread sleep for a period of time and will hold the lock of the thread;

 

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326082154&siteId=291194637