线程练习题

有三个线程,分别只能打印A,B和C,要求按顺序打印ABC,打印10次

输出示例:

ABC

ABC

ABC

ABC

ABC

ABC

ABC

ABC

ABC

ABC

(1)、这种方法并不能达到题目要求,因为无法确认当线程A在打印完一次后释放锁并唤醒其他线程时,它会唤醒线程B和线程C中的哪一个。这就导致,线程的执行顺序可能是ACB,也可能是其他顺序。

java 复制代码
public class Demo25 {

    public static void main(String[] args) {
        final Object lock = new Object();
        Thread a = new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                synchronized (lock) {
                    System.out.print("A");
                    lock.notifyAll();
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                    }
                }
            }
        });

        Thread b = new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                synchronized (lock) {
                    System.out.print("B");
                    lock.notifyAll();
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                    }
                }
            }
        });

        Thread c = new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                synchronized (lock) {
                    System.out.println("C");
                    lock.notifyAll();
                    try {
                        if (i < 9) {
                            lock.wait();
                        }
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                    }
                }
            }
        });

        a.start();
        b.start();
        c.start();
    }
}

(2)、我们刚刚写的代码中的线程因为没有合适的条件判断从而不能够按相应的顺序打印字母,又因为没有终止条件,所以无法正常停止。

现在改进以上错误,重新写一个实现方法:

java 复制代码
public class Thread_1{

    // 计数器
    // 定义一个单独的锁对象
    
    private static volatile int COUNTER = 0;
    private static Object lock = new Object();
   
    public static void main(String[] args) {
        // 创建三个线程,并指定线程名,每个线程名分别用A,B,C表示
        Thread t1 = new Thread(() -> {
            // 循环10次
            for (int i = 0; i < 10; i++) {
                // 执行的代码加锁
                synchronized (lock) {

                    // 每次唤醒后都重新判断是否满足条件
                    // 每条线程判断的条件不一样,注意线程t1,t2

                    while (COUNTER % 3 != 0) {
                        try {
                            // 不满足输出条件时,主动等待并释放锁
                            lock.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }

                    // 满足输出条件,打印线程名,每条线程打印的内容不同
                    System.out.print(Thread.currentThread().getName());
                    // 累加计数
                    COUNTER++;
                    // 唤醒其他线程
                    lock.notifyAll();
                }
            }
    }, "A");//线程被命名为 "A"

    Thread t2 = new Thread(() -> {
        for (int i = 0; i < 10; i++) {
            synchronized (lock) {
                while (COUNTER % 3 != 1) {
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.print(Thread.currentThread().getName());
                COUNTER++;
                lock.notifyAll();
            }
        }
    }, "B");

    Thread t3 = new Thread(() -> {
        for (int i = 0; i < 10; i++) {
            synchronized (lock) {
                while (COUNTER % 3 != 2) {
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                //换行打印
                System.out.println(Thread.currentThread().getName());
                COUNTER++;
                lock.notifyAll();
            }
        }
    }, "C");

    // 启动线程
        t1.start();
        t2.start();
        t3.start();
    }
}

代码 Thread_1 停下来的原因是每个线程都在循环中执行一定次数,并且使用了 lock.wait() 来等待条件满足。当满足条件后,线程会继续执行,否则会等待。

具体来说,代码中的三个线程 t1、t2、t3 会依次执行,它们之间使用了 lock 对象来同步,确保每次只有一个线程可以进入临界区执行。每个线程都有自己的条件检查,例如 t1 检查 COUNTER % 3 是否等于 0,t2 检查 COUNTER % 3 是否等于 1,t3 检查 COUNTER % 3 是否等于 2。这些条件控制了线程的执行顺序,确保了按照 "ABCABCABC" 的顺序输出。

当线程执行完一轮后,会通过 lock.wait() 主动释放锁并等待唤醒,然后其他线程会继续执行,直到满足条件后再次唤醒等待的线程。这种方式保证了线程的有序执行。

总之,这个代码中的线程之间使用了条件判断和等待来控制执行顺序,因此能够正常停止。

3、还有一种实现方法,就是使用三个锁, 分别控制。

java 复制代码
public class Demo26 {
    private static Object locker1 = new Object();
    private static Object locker2 = new Object();
    private static Object locker3 = new Object();

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            try {
                for (int i = 0; i < 10; i++) {
                    synchronized (locker1) {
                        locker1.wait();
                    }
                    System.out.print("A");
                    synchronized (locker2) {
                        locker2.notify();
                    }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        Thread t2 = new Thread(() -> {
            try {
                for (int i = 0; i < 10; i++) {
                    synchronized (locker2) {
                        locker2.wait();
                    }
                    System.out.print("B");
                    synchronized (locker3) {
                        locker3.notify();
                    }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        Thread t3 = new Thread(() -> {
            try {
                for (int i = 0; i < 10; i++) {
                    synchronized (locker3) {
                        locker3.wait();
                    }
                    //注意,只有C是println
                    System.out.println("C");
                    synchronized (locker1) {
                        locker1.notify();
                    }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        t1.start();
        t2.start();
        t3.start();

        Thread.sleep(1000);

        // 从线程 t1 启动
        synchronized (locker1) {
            locker1.notify();
        }
    }
}

再来看道题吧,和上面的差不多。

有三个线程,线程名称分别为:a,b,c。每个线程打印自己的名称。

需要让他们同时启动,并按 c,b,a 的顺序打印。

java 复制代码
public class PrintOrderDemo {
    private static final Object lock = new Object();
    private static volatile int turn = 0;

    public static void main(String[] args) {
        Thread threadA = new Thread(() -> {
            while (true) {
                synchronized (lock) {
                    while (turn != 2) {
                        try {
                            lock.wait();
                        } catch (InterruptedException e) {
                            Thread.currentThread().interrupt();
                        }
                    }
                    System.out.println("a");
                    turn = 0;
                    lock.notifyAll();
                }
            }
        });

        Thread threadB = new Thread(() -> {
            while (true) {
                synchronized (lock) {
                    while (turn != 1) {
                        try {
                            lock.wait();
                        } catch (InterruptedException e) {
                            Thread.currentThread().interrupt();
                        }
                    }
                    System.out.println("b");
                    turn = 2;
                    lock.notifyAll();
                }
            }
        });

        Thread threadC = new Thread(() -> {
            while (true) {
                synchronized (lock) {
                    while (turn != 0) {
                        try {
                            lock.wait();
                        } catch (InterruptedException e) {
                            Thread.currentThread().interrupt();
                        }
                    }
                    System.out.println("c");
                    turn = 1;
                    lock.notifyAll();
                }
            }
        });

        threadA.start();
        threadB.start();
        threadC.start();
    }
}
相关推荐
CoovallyAIHub3 小时前
181小时视频丢给GPT-5,准确率只有15%——南大联合NVIDIA等五校发布多模态终身理解数据集
深度学习·算法·计算机视觉
CoovallyAIHub3 小时前
CVPR 2026 | GS-CLIP:3D几何先验+双流视觉融合,零样本工业缺陷检测新SOTA,四大3D工业数据集全面领先!
深度学习·算法·计算机视觉
有意义5 小时前
深度拆解分割等和子集:一维DP数组与倒序遍历的本质
前端·算法·面试
用户726876103377 小时前
解放双手的健身助手:基于 Rokid AR 眼镜的运动计时应用
算法
Wect7 小时前
LeetCode 17. 电话号码的字母组合:回溯算法入门实战
前端·算法·typescript
ZhengEnCi1 天前
08c. 检索算法与策略-混合检索
后端·python·算法
程序员小崔日记1 天前
大三备战考研 + 找实习:我整理了 20 道必会的时间复杂度题(建议收藏)
算法·408·计算机考研
lizhongxuan1 天前
AI小镇 - 涌现
算法·架构
AI工程架构师1 天前
通常说算力是多少 FLOPS,怎么理解,GPU和CPU为什么差异这么大
算法
祈安_1 天前
Java实现循环队列、栈实现队列、队列实现栈
java·数据结构·算法