【Java面试】确保线程顺序执行的实现方法

简介: 【Java面试】确保线程顺序执行的实现方法

1.Thread.join()

我们来看看在 Java 7 Concurrency Cookbook 中相关的描述(很清楚地说明了 join() 的作用):

Waiting for the finalization of a thread
In some situations, we will have to wait for the finalization of a thread. For example, we may have a program that will begin initializing the resources it needs before proceeding with the rest of the execution. We can run the initialization tasks as threads and wait for its finalization before continuing with the rest of the program. For this purpose, we can use the join() method of the Thread class. When we call this method using a thread object, it suspends the execution of the calling thread until the object called finishes its execution.
当我们调用某个线程的这个方法时,这个方法会挂起调用线程,直到被调用线程结束执行,调用线程才会继续执行。内部使用了wait方法,和sleep的区别是,sleep不会释放锁,而wait会释放锁。
public class Main {
    public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(new Runnable() {

            @Override
            public void run() {
                System.out
                        .println(Thread.currentThread().getId() + "running...");
            }
        });

        Thread thread2 = new Thread(new Runnable() {

            @Override
            public void run() {
                System.out
                        .println(Thread.currentThread().getId() + "running...");
            }
        });

        Thread thread3 = new Thread(new Runnable() {

            @Override
            public void run() {
                System.out
                        .println(Thread.currentThread().getId() + "running...");
            }
        });
        thread1.start();
        thread1.join();

        thread2.start();
        thread2.join();

        thread3.start();
        thread3.join();
        System.out.println("Main Thread exit!");
    }
}

主线程这种按照顺序调用了thread1、thread2、thread3,main thread存当了调用者的角色。

2.自定义实现串行执行器

import java.util.ArrayDeque;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executor;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class Main {
    public static void main(String[] args) {
        Thread thread1 = new Thread(new Runnable() {

            @Override
            public void run() {
                System.out
                        .println(Thread.currentThread().getId() + "running...");
            }
        });

        Thread thread2 = new Thread(new Runnable() {

            @Override
            public void run() {
                System.out
                        .println(Thread.currentThread().getId() + "running...");
            }
        });

        Thread thread3 = new Thread(new Runnable() {

            @Override
            public void run() {
                System.out
                        .println(Thread.currentThread().getId() + "running...");
            }
        });

        SerialDefineExecutor defineExecutor = new SerialDefineExecutor();
        defineExecutor.execute(thread1);
        defineExecutor.execute(thread2);
        defineExecutor.execute(thread3);

        System.out.println("Main Thread exit!");
    }

    public static class SerialDefineExecutor implements Executor {
        ArrayDeque<Runnable> queue = new ArrayDeque<Runnable>();
        Runnable current = null;
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 10, 5,
                TimeUnit.SECONDS, sPoolWorkQueue);
        private static final BlockingQueue<Runnable> sPoolWorkQueue = new LinkedBlockingQueue<Runnable>(
                128);

        public SerialDefineExecutor() {
            threadPoolExecutor.allowCoreThreadTimeOut(true);
        }
        public synchronized void execute(Runnable runnable) {
            queue.offer(new Runnable() {

                @Override
                public void run() {
                    try {
                        runnable.run();
                    } finally {
                        next();
                    }
                }
            });
            if (current == null) {
                next();
            }
        }

        private synchronized void next() {
            if (!queue.isEmpty()) {
                current = queue.pop();
                threadPoolExecutor.execute(current);
            }
        }
    }
}

看过AsyncTask源码的各位,肯定看到过内部有这个串行执行器,保证内部线程的顺序执行,这里我们可以模仿写一个。

3.Thread.setPriority

设置线程优先级

public class Main {
    public static void main(String[] args) {
        Thread thread1 = new Thread(new Runnable() {

            @Override
            public void run() {
                System.out
                        .println(Thread.currentThread().getId() + "running...");
            }
        });

        Thread thread2 = new Thread(new Runnable() {

            @Override
            public void run() {
                System.out
                        .println(Thread.currentThread().getId() + "running...");
            }
        });

        Thread thread3 = new Thread(new Runnable() {

            @Override
            public void run() {
                System.out
                        .println(Thread.currentThread().getId() + "running...");
            }
        });

        thread1.setPriority(1);
        thread2.setPriority(2);
        thread3.setPriority(3);
        thread1.start();
        thread2.start();
        thread3.start();
        System.out.println("Main Thread exit!");
    }
}
目录
相关文章
|
6天前
|
存储 缓存 安全
【Java面试题汇总】多线程、JUC、锁篇(2023版)
线程和进程的区别、CAS的ABA问题、AQS、哪些地方使用了CAS、怎么保证线程安全、线程同步方式、synchronized的用法及原理、Lock、volatile、线程的六个状态、ThreadLocal、线程通信方式、创建方式、两种创建线程池的方法、线程池设置合适的线程数、线程安全的集合?ConcurrentHashMap、JUC
【Java面试题汇总】多线程、JUC、锁篇(2023版)
|
7天前
|
消息中间件 前端开发 NoSQL
面试官:线程池遇到未处理的异常会崩溃吗?
面试官:线程池遇到未处理的异常会崩溃吗?
37 3
面试官:线程池遇到未处理的异常会崩溃吗?
|
8天前
|
消息中间件 存储 前端开发
面试官:说说停止线程池的执行流程?
面试官:说说停止线程池的执行流程?
27 2
面试官:说说停止线程池的执行流程?
|
11天前
|
消息中间件 前端开发 NoSQL
面试官:如何实现线程池任务编排?
面试官:如何实现线程池任务编排?
21 1
面试官:如何实现线程池任务编排?
|
30天前
|
Java
【多线程面试题二十五】、说说你对AQS的理解
这篇文章阐述了对Java中的AbstractQueuedSynchronizer(AQS)的理解,AQS是一个用于构建锁和其他同步组件的框架,它通过维护同步状态和FIFO等待队列,以及线程的阻塞与唤醒机制,来实现同步器的高效管理,并且可以通过实现特定的方法来自定义同步组件的行为。
【多线程面试题二十五】、说说你对AQS的理解
|
16天前
|
存储 Java 程序员
优化Java多线程应用:是创建Thread对象直接调用start()方法?还是用个变量调用?
这篇文章探讨了Java中两种创建和启动线程的方法,并分析了它们的区别。作者建议直接调用 `Thread` 对象的 `start()` 方法,而非保持强引用,以避免内存泄漏、简化线程生命周期管理,并减少不必要的线程控制。文章详细解释了这种方法在使用 `ThreadLocal` 时的优势,并提供了代码示例。作者洛小豆,文章来源于稀土掘金。
|
23天前
|
算法 安全 Java
三种方法教你实现多线程交替打印ABC,干货满满!
本文介绍了多线程编程中的经典问题——多线程交替打印ABC。通过三种方法实现:使用`wait()`和`notify()`、`ReentrantLock`与`Condition`、以及`Semaphore`。每种方法详细讲解了实现步骤和代码示例,帮助读者理解和掌握线程间的同步与互斥,有效解决并发问题。适合不同层次的开发者学习参考。
42 11
|
17天前
|
Java Spring
运行@Async注解的方法的线程池
自定义@Async注解线程池
41 3
|
28天前
|
安全 Java API
|
30天前
|
消息中间件 缓存 算法
Java多线程面试题总结(上)
进程和线程是操作系统管理程序执行的基本单位,二者有明显区别: 1. **定义与基本单位**:进程是资源分配的基本单位,拥有独立的内存空间;线程是调度和执行的基本单位,共享所属进程的资源。 2. **独立性与资源共享**:进程间相互独立,通信需显式机制;线程共享进程资源,通信更直接快捷。 3. **管理与调度**:进程管理复杂,线程管理更灵活。 4. **并发与并行**:进程并发执行,提高资源利用率;线程不仅并发还能并行执行,提升执行效率。 5. **健壮性**:进程更健壮,一个进程崩溃不影响其他进程;线程崩溃可能导致整个进程崩溃。
34 2