【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
Java语言实现字母大小写转换的方法
Java提供了多种灵活的方法来处理字符串中的字母大小写转换。根据具体需求,可以选择适合的方法来实现。在大多数情况下,使用 String类或 Character类的方法已经足够。但是,在需要更复杂的逻辑或处理非常规字符集时,可以通过字符流或手动遍历字符串来实现更精细的控制。
421 18
|
6月前
|
Java 编译器 Go
【Java】(5)方法的概念、方法的调用、方法重载、构造方法的创建
Java方法是语句的集合,它们在一起执行一个功能。方法是解决一类问题的步骤的有序组合方法包含于类或对象中方法在程序中被创建,在其他地方被引用方法的优点使程序变得更简短而清晰。有利于程序维护。可以提高程序开发的效率。提高了代码的重用性。方法的名字的第一个单词应以小写字母作为开头,后面的单词则用大写字母开头写,不使用连接符。例如:addPerson。这种就属于驼峰写法下划线可能出现在 JUnit 测试方法名称中用以分隔名称的逻辑组件。
289 4
|
6月前
|
编解码 Java 开发者
Java String类的关键方法总结
以上总结了Java `String` 类最常见和重要功能性方法。每种操作都对应着日常编程任务,并且理解每种操作如何影响及处理 `Strings` 对于任何使用 Java 的开发者来说都至关重要。
388 5
|
7月前
|
算法 安全 Java
除了类,Java中的接口和方法也可以使用泛型吗?
除了类,Java中的接口和方法也可以使用泛型吗?
226 11
|
7月前
|
Java 开发者
Java 函数式编程全解析:静态方法引用、实例方法引用、特定类型方法引用与构造器引用实战教程
本文介绍Java 8函数式编程中的四种方法引用:静态、实例、特定类型及构造器引用,通过简洁示例演示其用法,帮助开发者提升代码可读性与简洁性。
|
7月前
|
存储 Oracle Java
|
7月前
|
算法 Java
50道java集合面试题
50道 java 集合面试题
|
7月前
|
算法 Java
50道java基础面试题
50道java基础面试题
时间轮-Java实现篇
在前面的文章《[时间轮-理论篇](https://developer.aliyun.com/article/910513)》讲了时间轮的一些理论知识,然后根据理论知识。我们自己来实现一个简单的时间轮。
1147 0