preface

This is a common question, I have also encountered, the following introduction of these several writing is also on concurrent programming tools to master a survey, is a good interview questions. There are a total of the following kinds of writing, the following are introduced respectively.

  1. Join (two ways of writing)
  2. Thread pool writing
  3. Wait and notify
  4. Condition of writing
  5. CountDownLatch writing
  6. CyclicBarrier writing
  7. Thread.sleep method
  8. CompletableFuture writing

The join of writing

The join() method joins the specified thread to the current thread, and can merge two alternating threads into sequential threads.

That is, the method t.join() blocks the calling thread from entering the TIMED_WAITING state until thread T completes, and then the thread continues.

Sequential execution of threads can be done in two ways, one in the main thread and one in child threads.

The main thread join

In the main method, t1.start is called to start the T1 thread, and then T1 join is called. The main thread where Main is located needs to wait for the completion of the RUN method in the T1 child thread before continuing to run. Therefore, the main thread is stuck before t2.start and waiting for the T1 program. After t1 runs, the main thread regains the initiative and continues to run t2.start and t2.join. Similar to the t1 sub-thread, the main thread waits for T2 to complete and continues to execute. In this way, the join method effectively solves the execution order problem. Because at the same point in time, each thread is synchronized.

public class MainJoin {

    static class MyThread implements Runnable {

        String name;

        public MyThread(String name) {
            this.name = name;
        }

        @Override
        public void run(a) {
            System.out.println(name + "Commence execution");
            try {
                // Todo business logic
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(name + "Executed"); }}public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(new MyThread("First thread"));
        Thread t2 = new Thread(new MyThread("Second thread"));
        Thread t3 = new Thread(new MyThread("Third thread")); t1.start(); t1.join(); t2.start(); t2.join(); t3.start(); }}Copy the code

To perform a

The child thread join

When writing the run method, let other threads join the queue and wait for the other threads to finish executing their logic.

public class SubJoin {

    static class MyThread implements Runnable {

        Thread thread;

        String name;

        public MyThread(Thread thread, String name) {
            this.thread = thread;
            this.name = name;
        }


        @Override
        public void run(a) {
            try {
                // let other threads jump the queue first
                if(thread ! =null) {
                    thread.join();
                }
                System.out.println(name + "Commence execution");
                // Execute your logic after todo finishes
                Thread.sleep(1000);
            } catch(Exception e) { e.printStackTrace(); }}}public static void main(String[] args) {
        Thread t1 = new Thread(new MyThread(null."First thread"));
        Thread t2 = new Thread(new MyThread(t1, "Second thread"));
        Thread t3 = new Thread(new MyThread(t2, "Third thread"));
        // Execute out of ordert3.start(); t1.start(); t2.start(); }}Copy the code

To perform a

Thread pool writing

Thread pool is also an interview must ask, must put its underlying source code, how to execute the principle of understanding, see can refer to the “thread pool source essence”. The sequential execution here is a clever use of 1 core thread number, 1 maximum thread number, to ensure that all tasks are executed sequentially.

public class ThreadPool {

    private static final ExecutorService executorService = new ThreadPoolExecutor(1.1.0L
            , TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>()
            , Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());


    static class MyThread implements Runnable {

        String name;

        public MyThread(String name) {
            this.name = name;
        }

        @Override
        public void run(a) {
            System.out.println(name + "Commence execution");
            try {
                // Todo executes business logic
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(name + "Executed"); }}public static void main(String[] args) {
        executorService.submit(new MyThread("First thread"));
        executorService.submit(new MyThread("Second thread"));
        executorService.submit(new MyThread("Third thread")); executorService.shutdown(); }}Copy the code

To perform a

Note: Thread poolsshutdownMethods andshutdownNowShutdownNow forces the execution of all threads in the thread pool to stop.

Wait and notify

Communication between threads:

Wait (): An Object method that causes the current thread to wait. Wait () also causes the current thread to release its lock. “Until another thread calls notify() or notifyAll() on this object,” the current thread is awakened (into the “ready state”).

Notify () and notifyAll(): notify() are methods on an Object that wake up the waiting thread on the current Object. Notify () wakes up a single thread, and notifyAll() wakes up all threads.

Wait (long timeout): To hold the current thread in the “waiting (blocking) state” until another thread calls notify() or notifyAll() of this object, or until the specified amount of time has elapsed. The current thread is awakened (in the “ready state”).

Threads T2 and T3 share the same lock myLock1. T2 blocks and waits for notify T2 to continue. T3 blocks and waits for notify T3 to continue.

The code is as follows:

public class WaitNotify {

    private static Object myLock1 = new Object();
    private static Object myLock2 = new Object();

    static class MyThread implements Runnable {

        String name;
        Object startLock;
        Object endLock;

        public MyThread(String name, Object startLock, Object endLock) {
            this.name = name;
            this.startLock = startLock;
            this.endLock = endLock;
        }

        @Override
        public void run(a) {
            if(startLock ! =null) {
                synchronized (startLock) {
                    / / blocking
                    try {
                        startLock.wait();
                    } catch(InterruptedException e) { e.printStackTrace(); }}}// Continue to execute
            System.out.println(name + "Commence execution");
            // Todo executes business logic
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if(endLock ! =null) {
                synchronized (endLock) {
                    / / wakeendLock.notify(); }}}}public static void main(String[] args) {
        Thread t1 = new Thread(new MyThread("First thread".null, myLock1));
        Thread t2 = new Thread(new MyThread("Second thread", myLock1, myLock2));
        Thread t3 = new Thread(new MyThread("Third thread", myLock2, null));
        // Execute out of ordert3.start(); t1.start(); t2.start(); }}Copy the code

To perform a

Condition of writing

Condition (Condition variable) : Usually associated with a lock. When you need to share a Lock across multiple contidions, you can pass an instance of Lock/RLock to the constructor, otherwise it will generate an instance of RLock itself.

  • The await() method in Condition is similar to the wait() method in Object.
  • The await(long time,TimeUnit Unit) method in Condition is similar to the wait(long time) method in Object.
  • The signal() method in Condition is similar to the notify() method in Object.
  • The signalAll() method in Condition is similar to the notifyAll() method in Object.

The syntax is similar to wait and notify

public class ConditionDemo {

    private static Lock lock = new ReentrantLock();
    private static Condition condition1 = lock.newCondition();
    private static Condition condition2 = lock.newCondition();

    static class MyThread implements Runnable {

        String name;
        Condition startCondition;
        Condition endCondition;

        public MyThread(String name, Condition startCondition, Condition endCondition) {
            this.name = name;
            this.startCondition = startCondition;
            this.endCondition = endCondition;
        }

        @Override
        public void run(a) {
            / / blocking
            if(startCondition ! =null) {
                lock.lock();
                try {
                    startCondition.await();
                } catch (Exception e) {
                    e.printStackTrace();
                } finally{ lock.unlock(); }}// Continue to execute
            System.out.println(name + "Commence execution");
            // Todo executes business logic
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            / / wake
            if(endCondition ! =null) {
                lock.lock();
                try {
                    endCondition.signal();
                } catch (Exception e) {
                    e.printStackTrace();
                } finally{ lock.unlock(); }}}}public static void main(String[] args) {
        Thread t1 = new Thread(new MyThread("First thread".null, condition1));
        Thread t2 = new Thread(new MyThread("Second thread", condition1, condition2));
        Thread t3 = new Thread(new MyThread("Third thread", condition2, null));
        // Execute out of ordert3.start(); t2.start(); t1.start(); }}Copy the code

To perform a

CountDownLatch writing

CountDownLatch is the counter. It has two methods, await(), which blocks, and countDown(), which count-1, which blocks await code when the count is 0.

It can block one thread or multiple threads, so it’s a shared lock. You can allow multiple threads to preempt the lock at the same time and then wake it up at the same time when the counter hits zero.

  • State record counter
  • CountDown, which is actually state–
public class CountDownLatchDemo {


    static class MyThread implements Runnable {
        CountDownLatch startCountDown;
        CountDownLatch endCountDown;

        public MyThread(CountDownLatch startCountDown, CountDownLatch endCountDown) {
            this.startCountDown = startCountDown;
            this.endCountDown = endCountDown;
        }

        @Override
        public void run(a) {
            / / blocking
            if(startCountDown ! =null) {
                try {
                    startCountDown.await();
                } catch(InterruptedException e) { e.printStackTrace(); }}// Execute your own business logic
            System.out.println(Thread.currentThread().getName() + "Commence execution");
            // Todo executes business logic
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if(endCountDown ! =null) { endCountDown.countDown(); }}}public static void main(String[] args) {
        CountDownLatch countDownLatch1 = new CountDownLatch(1);
        CountDownLatch countDownLatch2 = new CountDownLatch(1);
        Thread t1 = new Thread(new MyThread(null, countDownLatch1), "First thread");
        Thread t2 = new Thread(new MyThread(countDownLatch1, countDownLatch2), "Second thread");
        Thread t3 = new Thread(new MyThread(countDownLatch2, null), "Third thread");
        // Execute out of ordert3.start(); t2.start(); t1.start(); }}Copy the code

To perform a

CyclicBarrier writing

A CyclicBarrier is a barrier. It has only one method await(), which is equal to -1 and then blocks, and when reduced to 0, then executes all together, which is equal to ten thousand arrows.

1 block:

Execute down together for 0:

The code is as follows:

public class CyclicBarrierDemo {

    static class MyThread implements Runnable {

        CyclicBarrier startCyclicBarrier;

        CyclicBarrier endCyclicBarrier;

        public MyThread(CyclicBarrier startCyclicBarrier, CyclicBarrier endCyclicBarrier) {
            this.startCyclicBarrier = startCyclicBarrier;
            this.endCyclicBarrier = endCyclicBarrier;
        }

        @Override
        public void run(a) {
            / / blocking
            if(startCyclicBarrier ! =null) {
                try {
                    startCyclicBarrier.await();
                } catch(Exception e) { e.printStackTrace(); }}// Execute your own business logic
            System.out.println(Thread.currentThread().getName() + "Commence execution");
            // Todo executes business logic
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if(endCyclicBarrier ! =null) {
                try {
                    endCyclicBarrier.await();
                } catch(Exception e) { e.printStackTrace(); }}}}public static void main(String[] args) {
        CyclicBarrier barrier1 = new CyclicBarrier(2);
        CyclicBarrier barrier2 = new CyclicBarrier(2);
        Thread t1 = new Thread(new MyThread(null, barrier1), Thread 1 "");
        Thread t2 = new Thread(new MyThread(barrier1, barrier2), Thread 2 "");
        Thread t3 = new Thread(new MyThread(barrier2, null), "Thread 3");
        // Execute out of ordert3.start(); t2.start(); t1.start(); }}Copy the code

Execute:

Thread.sleep method

It’s kind of opportunistic, but it’s not efficient, you can’t do it in production, and you don’t know how long it takes for T1 to execute, how long it takes to sleep. You can say that in an interview, this is the right way to play b.

try {
      t1.start();
      Thread.sleep(1000);
      t2.start();
      Thread.sleep(1000);
      t3.start();
  } catch (InterruptedException e1) {
      e1.printStackTrace();
 }
Copy the code

The diagram below:

CompletableFuture writing

Before Java 8 came out, there were two ways to implement callbacks for tasks:

  • With the help ofFuture isDonePolling to determine whether the task is completed and obtain the result.
  • With the help ofGuavaThe class libraryListenableFuture, FutureCallback.(Netty has a similar implementation.)

Java8’s new CompletableFuture, borrowing from Netty’s transformation of Future, simplifies the complexity of asynchronous programming and provides the capability of functional programming. See Asynchronous Programming Future Mastering the Future for more details.

Here’s how to write it. Very simple. One sentence.

public class CompletableFutureDemo {

    static class MyThread implements Runnable {
        @Override
        public void run(a) {
            System.out.println("Execute:"+ Thread.currentThread().getName()); }}public static void main(String[] args) {
        Thread t1 = new Thread(new MyThread(), Thread 1 "");
        Thread t2 = new Thread(new MyThread(), Thread 2 "");
        Thread t3 = new Thread(new MyThread(), "Thread 3"); CompletableFuture.runAsync(t1::start).thenRun(t2::start).thenRun(t3::start); }}Copy the code

Execute:

conclusion

With regard to sequential execution of multiple threads, whether for an interview or a job, the solution to sequential execution of multiple threads is very important to master. Knowing so many writing methods, I have mastered 90% of concurrent programming. Many writing methods are so clever that I can write them easily only after I have mastered their principles. Thank you for watching

Source link: gitee.com/xiaojiebosh…