线程练习题

有三个线程,分别只能打印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();
    }
}
相关推荐
东方芷兰35 分钟前
算法笔记 04 —— 算法初步(下)
c++·笔记·算法
JNU freshman37 分钟前
图论 之 迪斯科特拉算法求解最短路径
算法·图论
青松@FasterAI1 小时前
【NLP算法面经】本科双非,头条+腾讯 NLP 详细面经(★附面题整理★)
人工智能·算法·自然语言处理
旅僧1 小时前
代码随想录-- 第一天图论 --- 岛屿的数量
算法·深度优先·图论
Emplace1 小时前
ABC381E题解
c++·算法
若兰幽竹2 小时前
【机器学习】衡量线性回归算法最好的指标:R Squared
算法·机器学习·线性回归
居然有人6543 小时前
23贪心算法
数据结构·算法·贪心算法
SylviaW083 小时前
python-leetcode 37.翻转二叉树
算法·leetcode·职场和发展
h^hh4 小时前
洛谷 P3405 [USACO16DEC] Cities and States S(详解)c++
开发语言·数据结构·c++·算法·哈希算法
玦尘、4 小时前
位运算实用技巧与LeetCode实战
算法·leetcode·位操作