用一个双线程轮流打印1-100
// 定义一个类,用于交替打印奇偶数
public class AlternatePrinting {// 当前待打印的数字,初始为1private int currentNumber = 1;// 用作线程间同步的锁对象private final Object lock = new Object();// 程序入口public static void main(String[] args) {// 创建类的实例AlternatePrinting ap = new AlternatePrinting();// 创建并启动打印奇数的线程Thread oddPrinter = new Thread(() -> ap.printNumbers(true));oddPrinter.start();// 创建并启动打印偶数的线程Thread evenPrinter = new Thread(() -> ap.printNumbers(false));evenPrinter.start();}// 根据传入的布尔值打印奇数或偶数private void printNumbers(boolean isOdd) {// 循环直到打印到100while (currentNumber <= 100) {// 同步块,确保线程安全synchronized (lock) {// 如果当前线程应该等待,则进入等待状态while ((isOdd && currentNumber % 2 == 0) || (!isOdd && currentNumber % 2 != 0)) {try {// 等待其他线程的通知lock.wait();} catch (InterruptedException e) {e.printStackTrace();}}// 打印当前数字,并声明是哪个线程打印的(奇数还是偶数)if (currentNumber <= 100) {System.out.println("Thread " + (isOdd ? "Odd" : "Even") + " printed: " + currentNumber);// 数字递增,准备下一次打印currentNumber++;// 通知其他等待中的线程lock.notifyAll();}}}}
}
三个线程顺序打出1-100
// 定义一个类,用于交替打印数字,利用三个线程
public class AlternatePrintingThreeThreads {// 当前待打印的数字,初始为1private int currentNumber = 1;// 用作线程间同步的锁对象private final Object lock = new Object();// 用于指示当前轮到哪个线程打印private int turn = 0;// 程序入口public static void main(String[] args) {// 创建类的实例AlternatePrintingThreeThreads ap = new AlternatePrintingThreeThreads();// 创建三个线程,分别负责打印序列中的不同部分Thread printer1 = new Thread(() -> ap.printNumbers(0));Thread printer2 = new Thread(() -> ap.printNumbers(1));Thread printer3 = new Thread(() -> ap.printNumbers(2));// 启动线程printer1.start();printer2.start();printer3.start();}/*** 打印数字的方法,按线程的偏移量打印数字* @param offset 线程的偏移值,决定了它应该打印哪些数字*/private void printNumbers(int offset) {// 循环直到打印到100while (currentNumber <= 100) {// 同步块,确保线程安全synchronized (lock) {// 等待直到轮到当前线程打印while ((turn % 3) != offset) {try {// 等待其他线程的通知lock.wait();} catch (InterruptedException e) {e.printStackTrace();}}// 打印当前数字,并声明是哪个线程打印的if (currentNumber <= 100) {System.out.println("Thread " + (offset + 1) + " printed: " + currentNumber);// 数字递增,准备下一次打印currentNumber++;// 轮转到下一个线程turn = (turn + 1) % 3;// 通知其他等待中的线程lock.notifyAll();}}}}
}
线程A,B,C分别打印数字1,2,3顺序执行10次
1 public class SequentialPrinting {
2
3 private int count = 0; // 用于控制当前执行的步骤
4 private final Object lock = new Object(); // 锁对象,用于同步控制
5
6 public static void main(String[] args) {
7 SequentialPrinting printer = new SequentialPrinting();
8
9 // 创建三个不同的线程,分别负责打印"A", "B", "C"
10 Thread threadA = new Thread(() -> printer.printNumber(1, "A"));
11 Thread threadB = new Thread(() -> printer.printNumber(2, "B"));
12 Thread threadC = new Thread(() -> printer.printNumber(3, "C"));
13
14 threadA.start(); // 启动线程A
15 threadB.start(); // 启动线程B
16 threadC.start(); // 启动线程C
17 }
18
19 private void printNumber(int numberToPrint, String letter) {
20 for (int i = 0; i < 10; i++) { // 每个线程打印10次
21 synchronized (lock) { // 进入同步块,确保线程安全
22 while (count % 3 != numberToPrint - 1) {
23 try {
24 lock.wait(); // 如果不是当前线程执行,则等待
25 } catch (InterruptedException e) {
26 e.printStackTrace();
27 }
28 }
29 if (count < 30) { // 确保总共只打印30次
30 System.out.println("Thread " + Thread.currentThread().getName() + " " + letter);
31 count++; // 计数器增加,控制打印次数和顺序
32 lock.notifyAll(); // 唤醒所有等待的线程
33 }
34 }
35 }
36 }
37 }
38
计数累加怎么线程安全,可以怎么实现,100个线程,每个累加1000次。
1 import java.util.concurrent.ExecutorService;
2 import java.util.concurrent.Executors;
3 import java.util.concurrent.TimeUnit;
4 import java.util.concurrent.atomic.AtomicInteger;
5
6 public class AtomicCounterDemo {
7
8 private static final AtomicInteger counter = new AtomicInteger(0); // 使用原子类保证线程安全的计数器
9
10 public static void main(String[] args) throws InterruptedException {
11 // 创建一个固定大小为100的线程池
12 ExecutorService executor = Executors.newFixedThreadPool(100);
13
14 // 提交100个任务到线程池,每个任务将计数器增加100次
15 for (int i = 0; i < 100; i++) {
16 executor.submit(new Runnable() {
17 @Override
18 public void run() {
19 for (int j = 0; j < 100; j++) {
20 counter.incrementAndGet(); // 安全地递增计数器
21 }
22 }
23 });
24 }
25
26 // 关闭线程池,不接受新任务
27 executor.shutdown();
28 // 等待所有任务完成,最多等待1小时
29 executor.awaitTermination(1, TimeUnit.HOURS);
30
31 // 输出最终的计数结果,预期为10000
32 System.out.println("Final count: " + counter.get());
33 }
34 }
线程交叉打印12A34B56C
1 public class CrossPrint {
2 private static final Object lock = new Object(); // 锁对象用于线程间的同步
3 private static boolean printNumber = true; // 控制打印流程的标志
4
5 public static void main(String[] args) {
6 // 创建并启动打印数字的线程
7 Thread printNumberThread = new Thread(() -> {
8 for (int i = 1; i <= 52; i += 2) { // 循环打印从1到51的奇数
9 synchronized (lock) {
10 while (!printNumber) { // 如果当前不是打印数字的轮次,等待
11 try {
12 lock.wait();
13 } catch (InterruptedException e) {
14 e.printStackTrace();
15 }
16 }
17 System.out.print(i); // 打印当前数字
18 System.out.print(i + 1); // 打印下一个数字
19 printNumber = false; // 设置标志为不打印数字
20 lock.notifyAll(); // 唤醒等待的线程
21 }
22 }
23 });
24
25 // 创建并启动打印字母的线程
26 Thread printLetterThread = new Thread(() -> {
27 for (char c = 'A'; c <= 'Z'; c++) { // 循环打印从A到Z的字母
28 synchronized (lock) {
29 while (printNumber) { // 如果当前是打印数字的轮次,等待
30 try {
31 lock.wait();
32 } catch (InterruptedException e) {
33 e.printStackTrace();
34 }
35 }
36 System.out.print(c); // 打印当前字母
37 printNumber = true; // 设置标志为打印数字
38 lock.notifyAll(); // 唤醒等待的线程
39 }
40 }
41 });
42
43 printNumberThread.start(); // 启动打印数字的线程
44 printLetterThread.start(); // 启动打印字母的线程
45 }
46 }
两个线程交替打印A- Z,一个大写一个小写。
1 public class AlternatePrinting {
2 private static final Object lock = new Object(); // 锁对象用于线程间同步
3 private static char currentLetter = 'A'; // 当前待打印的字母,初始为'A'
4 private static boolean printUpperCase = true; // 控制是否打印大写字母
5
6 public static void main(String[] args) {
7 // 创建并启动打印大写字母的线程
8 Thread upperCasePrinter = new Thread(() -> printLetters(true));
9 // 创建并启动打印小写字母的线程
10 Thread lowerCasePrinter = new Thread(() -> printLetters(false));
11
12 upperCasePrinter.start(); // 启动大写字母打印线程
13 lowerCasePrinter.start(); // 启动小写字母打印线程
14 }
15
16 private static void printLetters(boolean isUpperCaseThread) {
17 while (currentLetter <= 'Z') { // 循环直到打印到'Z'
18 synchronized (lock) {
19 while (printUpperCase != isUpperCaseThread) { // 等待直到符合当前线程的打印条件
20 try {
21 lock.wait(); // 等待其他线程的通知
22 } catch (InterruptedException e) {
23 e.printStackTrace(); // 打印中断异常
24 }
25 }
26 // 根据线程类型打印对应的字母大小写
27 if (isUpperCaseThread) {
28 System.out.print((char) currentLetter); // 打印大写字母
29 } else {
30 System.out.print(Character.toLowerCase((char) currentLetter)); // 打印小写字母
31 }
32
33 // 切换打印模式,并移到下一个字母
34 printUpperCase = !printUpperCase;
35 currentLetter++;
36
37 lock.notifyAll(); // 通知所有在等待锁的线程
38 }
39 }
40 }
41 }
打印a1b2...z26
1 public class AlternatePrinting {
2 private static final Object lock = new Object(); // 锁对象用于线程间同步
3 private static int count = 1; // 用于控制打印的数字和字母的序号
4 private static boolean printNumber = true; // 控制标志,true表示打印数字,false表示打印字母
5
6 public static void main(String[] args) {
7 // 创建并启动打印数字的线程
8 Thread printNumberThread = new Thread(() -> {
9 while (count <= 26) { // 打印从1到26的数字
10 synchronized (lock) {
11 while (!printNumber) { // 如果当前轮到打印字母,线程等待
12 try {
13 lock.wait(); // 等待其他线程调用notifyAll()
14 } catch (InterruptedException e) {
15 e.printStackTrace();
16 }
17 }
18 if (count <= 26) {
19 System.out.print(count); // 打印数字
20 count++; // 数字增加
21 printNumber = false; // 设置为打印字母
22 lock.notifyAll(); // 通知所有等待的线程
23 }
24 }
25 }
26 });
27
28 // 创建并启动打印字母的线程
29 Thread printLetterThread = new Thread(() -> {
30 while (count <= 26) { // 打印从A到Z的字母
31 synchronized (lock) {
32 while (printNumber) { // 如果当前轮到打印数字,线程等待
33 try {
34 lock.wait(); // 等待其他线程调用notifyAll()
35 } catch (InterruptedException e) {
36 e.printStackTrace();
37 }
38 }
39 if (count <= 26) {
40 char letter = (char) ('a' + count - 1); // 计算对应的字母
41 System.out.print(letter); // 打印字母
42 printNumber = true; // 设置为打印数字
43 lock.notifyAll(); // 通知所有等待的线程
44 }
45 }
46 }
47 });
48
49 // 启动两个线程
50 printNumberThread.start();
51 printLetterThread.start();
52 }
53 }
两个线程一个打abcd,一个打1234,交替打a1b2c3d4打10轮
1 public class AlternatePrintingDemo {
2 private static final Object lock = new Object(); // 锁对象用于线程间的同步
3 private static int state = 0; // 状态标志,0表示打印字母,1表示打印数字
4 private static int round = 0; // 轮次计数器,控制总共打印的轮次
5
6 public static void main(String[] args) {
7 // 创建并启动打印字母的线程
8 Thread printLetters = new Thread(() -> {
9 for (int i = 0; i < 40; i++) { // 循环打印40个字符(总共打印20轮)
10 synchronized (lock) {
11 while (state != 0) { // 当状态不为0时,等待打印数字
12 try {
13 lock.wait(); // 等待数字打印线程通知
14 } catch (InterruptedException e) {
15 e.printStackTrace();
16 }
17 }
18 if (round < 10) { // 仅当未达到10轮时执行打印
19 char letter = (char)('a' + (i % 4)); // 计算当前字母
20 System.out.print(letter); // 打印字母
21 state = 1; // 更改状态为打印数字
22 lock.notifyAll(); // 通知等待的数字打印线程
23 }
24 }
25 }
26 });
27
28 // 创建并启动打印数字的线程
29 Thread printNumbers = new Thread(() -> {
30 for (int i = 0; i < 40; i++) { // 循环打印40个数字(总共打印20轮)
31 synchronized (lock) {
32 while (state != 1) { // 当状态不为1时,等待打印字母
33 try {
34 lock.wait(); // 等待字母打印线程通知
35 } catch (InterruptedException e) {
36 e.printStackTrace();
37 }
38 }
39 if (round < 10) { // 仅当未达到10轮时执行打印
40 int number = (i % 4) + 1; // 计算当前数字
41 System.out.print(number); // 打印数字
42 if ((i + 1) % 4 == 0) {
43 round++; // 完成一轮后增加轮次计数
44 }
45 state = 0; // 更改状态为打印字母
46 lock.notifyAll(); // 通知等待的字母打印线程
47 }
48 }
49 }
50 });
51
52 // 启动两个线程
53 printLetters.start();
54 printNumbers.start();
55 }
56 }
有T1,T2,T3三个线程,怎么保证,T2 在T1后面执行,T3在T2 后面执行
// 定义一个名为ThreadJoinDemo的类
public class ThreadJoinDemo {// 主方法,程序的入口点public static void main(String[] args) {// 创建三个线程t1、t2和t3,每个线程都绑定了一个特定的任务Thread t1 = new Thread(new Task("T1"), "T1");Thread t2 = new Thread(new Task("T2"), "T2");Thread t3 = new Thread(new Task("T3"), "T3");// 启动线程t1t1.start();try {// 主线程调用t1.join(),意味着主线程将在此等待,直到t1执行完毕t1.join();// t1完成后,启动线程t2t2.start();// 主线程调用t2.join(),意味着主线程将在此等待,直到t2执行完毕t2.join();// t2完成后,启动线程t3t3.start();// 主线程调用t3.join(),意味着主线程将在此等待,直到t3执行完毕t3.join();} catch (InterruptedException e) {// 如果线程在等待过程中被中断,打印异常堆栈e.printStackTrace();}// 所有线程执行完成后输出System.out.println("所有线程现在都完成");}
}// 定义Task类,实现Runnable接口
class Task implements Runnable {// 线程的名字private String name;// 构造函数,设定线程的名字public Task(String name) {this.name = name;}// 线程执行的内容@Overridepublic void run() {// 输出开始执行的信息System.out.println(name + " 开始执行");try {// 线程休眠一段随机时间,模拟执行任务Thread.sleep((long) (Math.random() * 1000));} catch (InterruptedException e) {// 如果休眠被中断,打印异常堆栈e.printStackTrace();}// 输出执行完成的信息System.out.println(name + " 执行完毕");}
}
500张票,44个窗口,模拟购票流程,
// 定义一个名为TicketSystemDemo的类,用于演示售票系统
public class TicketSystemDemo {// 定义总票数为500张private static final int TOTAL_TICKETS = 500;// 定义剩余票数,初始值等于总票数private static int remainingTickets = TOTAL_TICKETS;// 创建一个对象作为锁,用于同步线程private static final Object lock = new Object();// 主方法,程序入口public static void main(String[] args) {// 创建四个售票窗口的线程for (int i = 1; i <= 4; i++) {new Thread(new TicketWindow(i)).start();}}// 定义一个实现Runnable接口的TicketWindow类,代表售票窗口static class TicketWindow implements Runnable {// 窗口号private int windowNumber;// 构造函数,初始化窗口号public TicketWindow(int windowNumber) {this.windowNumber = windowNumber;}// 实现run方法,定义线程的执行行为@Overridepublic void run() {// 使用死循环使窗口持续运行while (true) {// 使用synchronized块确保线程安全synchronized (lock) {// 检查是否还有剩余票数if (remainingTickets > 0) {// 调用buyTicket方法进行售票buyTicket();} else {// 如果没有剩余票数,输出提示信息并退出循环System.out.println("票已售完,窗口" + windowNumber + "关闭。");break;}}// 线程随机休眠一段时间,模拟真实的售票操作try {Thread.sleep((long) (Math.random() * 1000));} catch (InterruptedException e) {// 捕获并打印中断异常e.printStackTrace();}}}// 定义一个私有的buyTicket方法,用于售票private void buyTicket() {// 每次售票,剩余票数减一remainingTickets--;// 输出售票信息System.out.println("窗口" + windowNumber + "售出1张票,剩余" + remainingTickets + "张票");}}
}
// 导入需要的库
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;// 定义一个名为TaskRunner的公共类
public class TaskRunner {// 定义一个静态方法,用于分批运行任务public static void runTasksInBatches(List<Runnable> tasks, List<List<Integer>> batches) {// 创建一个固定大小为10的线程池ExecutorService executor = Executors.newFixedThreadPool(10);// 用于存储每个批次任务的Future对象List<Future<Void>> futures = new ArrayList<>();// 存储所有批次的任务索引,用于确保任务不被重复提交Set<Integer> allBatchTaskIndexes = new HashSet<>();// 遍历所有批次for (int i = 0; i < batches.size(); i++) {// 遍历当前批次的每个任务索引for (int index : batches.get(i)) {// 提交任务到线程池,并添加返回的Future到列表中Future<Void> future = (Future<Void>) executor.submit(tasks.get(index));futures.add(future);// 记录已提交的任务索引allBatchTaskIndexes.add(index);}}// 等待所有任务完成for (Future<Void> f : futures) {f.get(); // 阻塞直到任务完成}// 清除所有的Future对象futures.clear();// 提交未包含在批次中的任务for (int i = 0; i < tasks.size(); i++) {if (!allBatchTaskIndexes.contains(i)) {executor.submit(tasks.get(i));}}// 关闭执行器服务,不再接受新任务executor.shutdown();// 等待直到所有任务完成while (!executor.isTerminated()) {// 循环等待直到所有线程执行完毕}// 输出任务全部完成的信息System.out.println("所有任务均已完成");}// 主方法public static void main(String[] args) {// 创建一百个任务List<Runnable> tasks = createTasks(); // 创建任务列表// 定义两个任务批次List<Integer> batch1 = new ArrayList<>(Arrays.asList(1, 3, 5, 7));List<Integer> batch2 = new ArrayList<>(Arrays.asList(11, 13, 15, 17));// 将批次添加到批次列表List<List<Integer>> batchs = new ArrayList<>();batchs.add(batch1);batchs.add(batch2);// 执行分批运行任务的方法try {runTasksInBatches(tasks, batchs);System.out.println("所有任务执行完毕");} catch (Exception e) {e.printStackTrace();}}// 创建任务的方法private static List<Runnable> createTasks() {List<Runnable> tasks = new ArrayList<>();for (int i = 0; i < 30; i++) {final int taskId = i;// 将新任务添加到列表,每个任务输出一个任务号tasks.add(() -> System.out.println("执行任务 #" + taskId));}return tasks; // 返回任务列表}
}