Title: start two threads to print odd and even numbers from 0 to 100 alternately
You may have encountered this problem during the interview. Although you have learned the knowledge related to multithreading, you may not be able to write it for a while and a half. Now let me take you to write it again!
Method 1
First, we can observe that odd and even numbers are printed, so we can write code through this feature. If we have a global variable count, when count is equal to an even number, we will let thread 1 print. When count is equal to an odd number, we will let thread 2 print. So how? Here we can use locks to ensure that only one thread is executing at the same time. However, if the same thread always grabs the lock and the other thread doesn't get it, it will cause the thread to do a lot of meaningless idling, which is very inefficient and can't be favored by the interviewer.
The code is as follows:
public class Test { // Global variable count private int count = 0; // lock private final Object lock = new Object(); public static void main(String[] args) { Test test = new Test(); test.turning(); } public void turning() { Thread even = new Thread(() -> { while (count < 100) { // Acquire lock synchronized (lock) { // Only even numbers are processed if ((count & 1) == 0) { System.out.println(Thread.currentThread().getName() + ": " + count++); } } } }, "even numbers"); Thread odd = new Thread(() -> { while (count < 100) { // Acquire lock synchronized (lock) { // Only odd numbers are processed if ((count & 1) == 1) { System.out.println(Thread.currentThread().getName() + ": " + count++); } } } }, "Odd number"); even.start(); odd.start(); } }
Method 2
Idea: the principle of this implementation is that thread 1 wakes up other threads after printing, then gives up the lock and enters the sleep state. Because when you enter the sleep state, you will not grab the lock with other threads. At this time, only thread 2 is acquiring the lock, so thread 2 is bound to get the lock. Thread 2 executes with the same logic, wakes up thread 1, gives up the lock it holds, and enters the sleep state. This goes back and forth and continues until the task is completed. This achieves the effect of two threads obtaining locks alternately.
The code is as follows:
public class Test { // Global variable count private int count = 0; // lock private final Object lock = new Object(); public static void main(String[] args) throws InterruptedException { Test test = new Test(); test.turning(); } public void turning() throws InterruptedException { new Thread(new TurningRunner(), "even numbers").start(); // Ensure that even threads acquire locks first Thread.sleep(1); new Thread(new TurningRunner(), "Odd number").start(); } class TurningRunner implements Runnable { @Override public void run() { while (count <= 100) { // Acquire lock synchronized (lock) { // Print when you get the lock System.out.println(Thread.currentThread().getName() + ": " + count++); // Wake up other threads lock.notifyAll(); try { if (count <= 100) { // If the task is not finished, release the current lock and sleep lock.wait(); } } catch (InterruptedException e) { e.printStackTrace(); } } } } } }
Mode III
Semaphore implementation
The code is as follows:
public class PrintNum { private int n; private Semaphore odd = new Semaphore(1); private Semaphore even = new Semaphore(0); public PrintNum(int n) { this.n = n; } public void printOdd() { for (int i=1; i<=n; i+=2) { try { odd.acquire(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Odd number" + i); even.release(); } } public void printEven() { for(int i=2; i<=n; i+=2) { try { even.acquire(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("even numbers" + i); odd.release(); } } public static void main(String[] args){ PrintNum printNum = new PrintNum(100); ExecutorService executorService = Executors.newFixedThreadPool(2); executorService.submit(() -> { printNum.printOdd(); }); executorService.submit(() -> { printNum.printEven(); }); executorService.shutdown(); } }
Tips:
acquire(): acquire a license
release(): release the license
Mode 4
Using the continuation implementation, let's look at the code. The code is more intuitive
The code is as follows:
public class PrintNumThreadTest { public static void main(String[] args) { PrintNumOpt printNumOpt = new PrintNumOpt(); new Thread(() -> printNumOpt.print0()).start(); new Thread(() -> printNumOpt.print1()).start(); } } class PrintNumOpt { int num = 0; int opt = 0; int maxNum = 100; ReentrantLock lock = new ReentrantLock(); /** * even numbers */ Condition condition0 = lock.newCondition(); /** * Odd number */ Condition condition1 = lock.newCondition(); public void print0() { while (this.opt == 0) { lock.lock(); try { for (; num < maxNum; num++) { if (num % 2 == 0) { System.out.println("even numbers:" + num); this.opt = 1; condition1.signal(); condition0.await(); } } } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } } public void print1() { while (this.opt == 1) { lock.lock(); try { for (; num < maxNum; num++) { if (num % 2 == 1) { System.out.println("Odd:" + num); this.opt = 0; condition0.signal(); condition1.await(); } } } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } } }
Tips:
public void await() causes the current thread to wait until a signal or interrupt signal is issued
public void signal() wakes up a waiting thread
public void signalAll() wakes up all waiting threads
extend
Title: three threads print 1, 2 and 3 alternately; 4,5,6…
Let's think about it first. I have time to write an article 🤣🤣🤣
quote:
https://blog.csdn.net/dadiyang/article/details/88315124
https://www.jianshu.com/p/72914f43a19f
https://www.cxymm.net/article/bobo1356/103408137