线程练习题

有三个线程,分别只能打印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();
    }
}
相关推荐
Fuxiao___5 分钟前
不使用递归的决策树生成算法
算法
我爱工作&工作love我11 分钟前
1435:【例题3】曲线 一本通 代替三分
c++·算法
白-胖-子1 小时前
【蓝桥等考C++真题】蓝桥杯等级考试C++组第13级L13真题原题(含答案)-统计数字
开发语言·c++·算法·蓝桥杯·等考·13级
workflower1 小时前
数据结构练习题和答案
数据结构·算法·链表·线性回归
好睡凯1 小时前
c++写一个死锁并且自己解锁
开发语言·c++·算法
Sunyanhui11 小时前
力扣 二叉树的直径-543
算法·leetcode·职场和发展
一个不喜欢and不会代码的码农1 小时前
力扣105:从先序和中序序列构造二叉树
数据结构·算法·leetcode
前端郭德纲1 小时前
浏览器是加载ES6模块的?
javascript·算法
SoraLuna1 小时前
「Mac玩转仓颉内测版10」PTA刷题篇1 - L1-001 Hello World
算法·macos·cangjie
白-胖-子2 小时前
【蓝桥等考C++真题】蓝桥杯等级考试C++组第13级L13真题原题(含答案)-成绩排序
c++·算法·蓝桥杯·真题·蓝桥等考