手撕多线程

用一个双线程轮流打印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; // 返回任务列表
    }
}

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值