多线程轮流打印

本文通过一个常见的面试题——两个线程交替打印字符串和数字,详细解析了Java中wait()和notify()方法的使用。通过示例代码展示了如何控制线程间的协作,以及在多个线程环境下如何扩展这一机制,如增加到三个线程的交替打印。同时,文章也探讨了在不同类中共享标志位的方法。
摘要由CSDN通过智能技术生成

一、背景

面试的时候,有一个高频的笔试题:

让2个线程轮流打印,a线程是打印ABCDEFGHIJ,b线程是打印1、2、3、4、5、6、7、8、9、10

二、原理

这种类型的面试题,主要是考察object的wait()方法和notify()方法的使用

wait()方法用法:

o.wait()会让正在o对象上活动的当前线程进入等待状态,并且释放之前占用的o对象的锁

notify()方法用法:

o.notify()唤醒正在o对象上等待的线程, 只会通知,不会释放之前占用的o对象的锁

三、用法

2个线程轮流打印,a线程是打印ABCDEFGHIJ,b线程是打印1、2、3、4、5、6、7、8、9、10

package com.iflytek.sda;

import java.util.Arrays;
import java.util.List;

public class ThreadTest {

    private static final Object lock = new Object();

    private static boolean ifPrint = false;

    public static void main(String[] args) {
        Thread ta = new Thread(() ->{
            // 要打印的list
            List<String> list = Arrays.asList("A","B","C","D","E","F","G","H","I","J");
                for (int i = 0; i < list.size(); i++){
                    synchronized (lock) {
                        // 如果ifPrint的值为true,就会进入等待状态
                        while (ifPrint) {
                            try{
                                lock.wait();
                            }catch (Exception e){

                            }
                        }
                        // 到了这一步,说明ifPrint的值为false,然后就会打印
                        System.out.print(list.get(i));
                        // 修改ifPrint的值为true,这样再次进入该方法时会进入等待状态,不会进行打印
                        ifPrint = true;
                        // 唤醒正在lock对象上等待的线程
                        lock.notify();
                    }
                }
        });
        Thread tb = new Thread(() ->{
            for (int i = 0; i < 10; i++){
                synchronized (lock) {
                    // 如果ifPrint的值为false,就会进入等待状态
                    while (!ifPrint) {
                        try{
                            lock.wait();
                        }catch (Exception e){

                        }
                    }
                    // 到了这一步,说明ifPrint的值为true,然后就会打印
                    System.out.print(i+1);
                    // 修改ifPrint的值为false,这样再次进入该方法时会进入等待状态,不会进行打印
                    ifPrint = false;
                    // 唤醒正在lock对象上等待的线程
                    lock.notify();
                }
            }
        });
        ta.start();
        tb.start();
    }
}

一开始,ifPrint为false,此时,ta线程会进行打印,打印A;tb线程会处于等待状态;

等ta打印完毕,修改ifPrint为true,并且唤醒其它等待线程。

此时,ta线程会处于等待状态;tb线程会进行打印,打印1

等tb打印完毕,修改ifPrint为false,并且唤醒其它等待线程。

此时,ta线程会进行打印,打印B;tb线程会处于等待状态;

....

以此类推:

 四、升级

上面是2个线程,可以通过true、false的两种状态来区分,那如果是3个线程呢,4个线程呢,要怎么办?

3个线程,轮流打印,第一个线程只打印A,第二个线程只打印B,第三个线程只打印C

package com.iflytek.sda;


public class ThreadTest2 {

    private static Integer flag = 1;

    private static final Object lock = new Object();

    public static void main(String[] args) {

        Thread threadA = new Thread(()->{
            for (int i = 0 ; i < 10; i++){
                synchronized (lock){
                    while(flag != 1){
                        try{
                            lock.wait();
                        }catch (Exception e){

                        }
                    }
                    System.out.print("A");
                    flag = 2;
                    lock.notifyAll();
                }
            }
        });
        Thread threadB = new Thread(()->{
            for (int i = 0 ; i < 10; i++){
                synchronized (lock){
                    while(flag != 2){
                        try{
                            lock.wait();
                        }catch (Exception e){

                        }
                    }
                    System.out.print("B");
                    flag = 3;
                    lock.notifyAll();
                }
            }
        });
        Thread threadC = new Thread(()->{
            for (int i = 0 ; i < 10; i++){
                synchronized (lock){
                    while(flag != 3){
                        try{
                            lock.wait();
                        }catch (Exception e){

                        }
                    }
                    System.out.print("C");
                    flag = 1;
                    lock.notifyAll();
                }
            }
        });
        threadA.start();
        threadB.start();
        threadC.start();
    }
}

这里的代码写在同一个类里面,标志位写在最上面可以共用,实际用法中都不在一个类里面,要怎么办呢?

package com.example.demo.thread;

public class ThreadPrint {

    public static Integer flag = 1;
    public static void main(String[] args) {

        Thread ta = new Thread(new ThreadA());
        Thread tb = new Thread(new ThreadB());
        ta.start();
        tb.start();
    }
}

class ThreadA implements Runnable{

    @Override
    public void run() {
        for(int i = 0 ; i < 10; i++){
            synchronized (ThreadPrint.class){
                while (ThreadPrint.flag != 1){
                    try {
                        ThreadPrint.class.wait();
                    }catch (Exception e){

                    }
                }
                System.out.print("1");
                ThreadPrint.flag = 2;
                ThreadPrint.class.notifyAll();
            }
        }
    }
}

class ThreadB implements Runnable{

    @Override
    public void run() {
        for(int i = 0 ; i < 10; i++){
            synchronized (ThreadPrint.class){
                while (ThreadPrint.flag != 2){
                    try {
                        ThreadPrint.class.wait();
                    }catch (Exception e){

                    }
                }
                System.out.print("A");
                ThreadPrint.flag = 1;
                ThreadPrint.class.notifyAll();
            }
        }
    }
}

好几个线程同理,

另外,超过两个线程就需要使用notifyAll,唤醒对象上的所有线程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值