网站首页 > 精选教程 正文
在Java中控制多线程执行顺序的方式有很多种,下面我们就来介绍一下再开发中常用的控制多线程执行顺序的方式。
join() 方法
Thread.join()方法可以让一个线程等待另一个线程执行完成后再继续执行。例如,线程A可以调用线程B的join()方法,线程A会等待线程B执行完成后才会继续执行,如下所示。
public class JoinExample {
public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
System.out.println("Thread 1 is running");
});
Thread thread2 = new Thread(() -> {
System.out.println("Thread 2 is running");
});
thread1.start();
try {
thread1.join(); // 主线程等待 thread1 结束
} catch (InterruptedException e) {
e.printStackTrace();
}
thread2.start();
}
}
在上述代码中,main方法会等待thread1完成后再执行thread2,保证了执行顺序。
wait() 和 notify() 机制
当然除了上面的方式之外,Java中还提供了两个对象级的方法,可以通过锁机制实现线程间通信和顺序控制。通常结合synchronized关键字来实现同步,如下所示。
public class WaitNotifyExample {
private static final Object lock = new Object();
public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
synchronized (lock) {
System.out.println("Thread 1 is running");
lock.notify(); // 唤醒等待的线程
}
});
Thread thread2 = new Thread(() -> {
synchronized (lock) {
try {
lock.wait(); // 等待唤醒
System.out.println("Thread 2 is running");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
thread2.start();
thread1.start();
}
}
在上面的代码中,thread2会等待,直到thread1执行完并调用lock.notify()后才继续执行。这可以确保thread1先于thread2执行。
CountDownLatch
CountDownLatch是一个同步工具类,可以允许一个或多个线程等待其他线程完成操作。其内部设置了一个计数器,当计数器倒数到零的时候释放所有等待线程,如下所示。
import java.util.concurrent.CountDownLatch;
public class CountDownLatchExample {
public static void main(String[] args) {
CountDownLatch latch = new CountDownLatch(1);
Thread thread1 = new Thread(() -> {
System.out.println("Thread 1 is running");
latch.countDown(); // 计数器减一
});
Thread thread2 = new Thread(() -> {
try {
latch.await(); // 等待计数器归零
System.out.println("Thread 2 is running");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
thread2.start();
thread1.start();
}
}
这里的thread2会在latch计数器减到0之前保持等待,而thread1在完成任务后调用countDown(),使thread2可以继续执行。
使用CyclicBarrier
CyclicBarrier允许一组线程互相等待,直到它们都达到一个共同的屏障点。适合用于需要多个线程同步执行到某个步骤的场景。
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class CyclicBarrierExample {
public static void main(String[] args) {
CyclicBarrier barrier = new CyclicBarrier(2); // 需要 2 个线程到达屏障点
Thread thread1 = new Thread(() -> {
try {
System.out.println("Thread 1 is running");
barrier.await(); // 等待其他线程
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println("Thread 1 continues");
});
Thread thread2 = new Thread(() -> {
try {
System.out.println("Thread 2 is running");
barrier.await(); // 等待其他线程
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println("Thread 2 continues");
});
thread1.start();
thread2.start();
}
}
在这个例子中,thread1和thread2都调用barrier.await(),只有两个线程都到达屏障点后才会继续执行“Thread X continues”。
使用Semaphore
Semaphore是一种计数信号量,用来控制访问特定资源的线程数量。在需要顺序时,可以设置信号量的初始许可数为0,让线程互相通知。
import java.util.concurrent.Semaphore;
public class SemaphoreExample {
private static Semaphore semaphore = new Semaphore(0);
public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
System.out.println("Thread 1 is running");
semaphore.release(); // 增加一个许可
});
Thread thread2 = new Thread(() -> {
try {
semaphore.acquire(); // 等待一个许可
System.out.println("Thread 2 is running");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
thread2.start();
thread1.start();
}
}
在这里,thread2会在semaphore获得许可之前阻塞,而thread1在完成后通过调用release() 来释放一个许可,使得thread2得以继续执行。
使用Future 和 ExecutorService
ExecutorService提供了异步任务执行的控制,可以提交多个任务,并通过Future.get()阻塞地等待任务完成,从而实现顺序控制。
import java.util.concurrent.*;
public class FutureExample {
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(2);
Callable<String> task1 = () -> {
System.out.println("Task 1 is running");
return "Result of Task 1";
};
Callable<String> task2 = () -> {
System.out.println("Task 2 is running");
return "Result of Task 2";
};
try {
Future<String> future1 = executor.submit(task1);
future1.get(); // 等待 task1 完成
Future<String> future2 = executor.submit(task2);
future2.get(); // 等待 task2 完成
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
} finally {
executor.shutdown();
}
}
}
这里,future1.get()会等待task1执行完成,然后才会执行task2。
总结
上面这些方式提供了在Java中控制线程执行顺序的常用方式,这些方法在不同场景下可以灵活使用,我们可以根据实际情况选择合适的机制来控制线程的执行顺序。
猜你喜欢
- 2024-11-19 你知道@Async 是怎么让方法异步执行的吗?
- 2024-11-19 Java 并发编程 11 - 异步执行框架 Executor
- 2024-11-19 Java中异步复用io
- 2024-11-19 JAVA异步方法笔记
- 2024-11-19 面试官:Redis分布式锁超时了,任务还没执行完怎么办?
- 2024-11-19 万能通用的异步实战方案,设计多线程,mq
- 2024-11-19 Java客户端Jedis 对Redis的几种调用方式包括事务、管道、分布式
- 2024-11-19 Dubbo 2.7新特性之异步化改造
- 2024-11-19 新手也能看懂的 SpringBoot 异步编程指南
- 2024-11-19 SpringBoot 异步编程
你 发表评论:
欢迎- 04-11Java面试“字符串三兄弟”String、StringBuilder、StringBuffer
- 04-11Java中你知道几种从字符串中找指定的字符的数量
- 04-11探秘Java面试中问的最多的String、StringBuffer、StringBuilder
- 04-11Python字符串详解与示例(python字符串的常见操作)
- 04-11java正则-取出指定字符串之间的内容
- 04-11String s1 = new String("abc");这句话创建了几个字符串对象?
- 04-11java判断字符串中是否包含某个字符
- 04-11关于java开发中正确的发牌逻辑编写规范
- 最近发表
-
- Java面试“字符串三兄弟”String、StringBuilder、StringBuffer
- Java中你知道几种从字符串中找指定的字符的数量
- 探秘Java面试中问的最多的String、StringBuffer、StringBuilder
- Python字符串详解与示例(python字符串的常见操作)
- java正则-取出指定字符串之间的内容
- String s1 = new String("abc");这句话创建了几个字符串对象?
- java判断字符串中是否包含某个字符
- 关于java开发中正确的发牌逻辑编写规范
- windows、linux如何后台运行jar(并且显示进程名)
- 腾讯大佬私人收藏,GitHub上最受欢迎的100个JAVA库,值得学习
- 标签列表
-
- nginx反向代理 (57)
- nginx日志 (56)
- nginx限制ip访问 (62)
- mac安装nginx (55)
- java和mysql (59)
- java中final (62)
- win10安装java (72)
- java启动参数 (64)
- java链表反转 (64)
- 字符串反转java (72)
- java逻辑运算符 (59)
- java 请求url (65)
- java信号量 (57)
- java定义枚举 (59)
- java字符串压缩 (56)
- java中的反射 (59)
- java 三维数组 (55)
- java插入排序 (68)
- java线程的状态 (62)
- java异步调用 (55)
- java中的异常处理 (62)
- java锁机制 (54)
- java静态内部类 (55)
- java怎么添加图片 (60)
- java 权限框架 (55)
本文暂时没有评论,来添加一个吧(●'◡'●)