用一个双线程轮流打印1-100
// 定义一个类,用于交替打印奇偶数
public class AlternatePrinting {
// 当前待打印的数字,初始为1
private 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) {
// 循环直到打印到100
while (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 {
// 当前待打印的数字,初始为1
private 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) {
// 循环直到打印到100
while (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");
// 启动线程t1
t1.start();
try {
// 主线程调用t1.join(),意味着主线程将在此等待,直到t1执行完毕
t1.join();
// t1完成后,启动线程t2
t2.start();
// 主线程调用t2.join(),意味着主线程将在此等待,直到t2执行完毕
t2.join();
// t2完成后,启动线程t3
t3.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;
}
// 线程执行的内容
@Override
public 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方法,定义线程的执行行为
@Override
public 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; // 返回任务列表
}
}