【并发编程】多线程实际操作测试题

经典面试题
下面是多线程顺序打印的经典面试题

1.三个线程分别打印 A,B,C,要求这三个线程一起运行,打印 n 次,输出形如“ABCABCABC…”的字符串

2.两个线程交替打印 0~100 的奇偶数

3.通过 N 个线程顺序循环打印从 0 至 100

4.多线程按顺序调用,A->B->C,AA 打印 5 次,BB 打印10 次,CC 打印 15 次,重复 10 次

5.用两个线程,一个输出字母,一个输出数字,交替输出 1A2B3C4D…26Z

6.利用两个线程,分别计算 0-n/2 和 n/2-n的和,然后返回和

思路:要么控制线程顺序,要么利用条件竞争锁


Semaphore

 public static void main(String[] args) {

        Semaphore s1 = new Semaphore(1);
        Semaphore s2 = new Semaphore(0);
        Semaphore s3 = new Semaphore(0);

        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    s1.acquire();
                    System.out.println("A");
                    s2.release();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    s2.acquire();
                    System.out.println("B");
                    s3.release();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        Thread t3 = new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    s3.acquire();
                    System.out.println("C");
                    s1.release();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        t1.start();
        t2.start();
        t3.start();
    }

第一题

    public static void test(int nums){
        Semaphore s1 = new Semaphore(1);
        Semaphore s2 = new Semaphore(0);
        AtomicInteger x = new AtomicInteger(0);
        Thread t1 = new Thread(() -> {
            try {
                for (int i = 0; i < nums/2; i++) {
                    s1.acquire();
                    System.out.println("线程1   " + x);
                    x.getAndIncrement();
                    s2.release();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        Thread t2 = new Thread(() -> {
            try {
                for (int i = 0; i < nums/2; i++) {
                    s2.acquire();
                    System.out.println("线程2  " + x);
                    x.getAndIncrement();
                    s1.release();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        t1.start();
        t2.start();
    }

第二题


使用 wait/notify

public class BBB {
    Object object = new Object();
    public int state;
    public int times;

    public BBB(int times) {
        this.times = times;
    }

    public void printABC(String name,int currentstate){
        for (int i = 0; i < times; i++)
            synchronized (object) {
                while (state % 3 != currentstate) {
                    try {
                        object.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                state++;
                System.out.print(name);
                object.notifyAll();
            }
    }

    public static void main(String[] args) {
        BBB bbb = new BBB(10);
        new Thread(()->{
            bbb.printABC("A",0);
        }).start();
        new Thread(()->{
            bbb.printABC("B",1);
        }).start();
        new Thread(()->{
            bbb.printABC("C",2);
        }).start();
    }
}

第一题

思路:还是以第一题为例,我们用对象监视器来实现,通过 wait 和 notify() 方法来实现等待、通知的逻辑,A 执行后,唤醒 B,B 执行后唤醒 C,C 执行后再唤醒 A,这样循环的等待、唤醒来达到目的

public class OddEvenPrinter {

    private Object object = new Object();
    private final int limit;
    private volatile int count;

    OddEvenPrinter(int initCount, int times) {
        this.count = initCount;
        this.limit = times;
    }

    private void print() {

        synchronized (object) {
            while (count < limit){
                try {
                    System.out.println(String.format("线程[%s]打印数字:%d", Thread.currentThread().getName(), ++count));
                    object.notifyAll();   //通知宁外一个线程进入抢锁状态
                    object.wait();        //释放锁,此线程进入等待队列
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            //防止有子线程被阻塞未被唤醒,导致主线程不退出
            object.notifyAll();
        }
    }

    public static void main(String[] args) {
        OddEvenPrinter printer = new OddEvenPrinter(0, 100);
        new Thread(printer::print, "奇数").start();
        new Thread(printer::print, "偶数").start();
    }

}

第二题

思路:使用对象监视器实现,两个线程 A、B 竞争同一把锁,只要其中一个线程获取锁成功,就打印 ++i,并通知另一线程从等待集合中释放,然后自身线程加入等待集合并释放锁即可


使用Lock(ReentrantLock)

package main.java.org.多线程Demo;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @param
 * @author XiaoSuDa
 * @description: $
 * @return $
 * @throws
 * @date $ $
 */


public class PrinterABC {
    private int times; // 控制打印次数
    private int state;   // 当前状态值:保证三个线程之间交替打印
    private Lock lock = new ReentrantLock();

    public PrinterABC(int times) {
        this.times = times;
    }
    
    public void print(String name,int currentState){
        for (int i = 0; i < times; ) {
            lock.lock();
            if (state % 3 == currentState){
                state++;
                i++;
                System.out.print(name);
            }
            lock.unlock();
        }
    }

    public static void main(String[] args) {
        //顺序打印10次
        PrinterABC printerABC = new PrinterABC(10);

        new Thread(() -> {
            printerABC.print("A", 0);
        }, "A").start();

        new Thread(() -> {
            printerABC.print("B", 1);
        }, "B").start();

        new Thread(() -> {
            printerABC.print("C", 2);
        }, "C").start();
    }
}

第一题

思路:使用一个取模的判断逻辑 C%M ==N,题为 3 个线程,所以可以按取模结果编号:0、1、2,他们与 3 取模结果仍为本身,则执行打印逻辑


CountDownLatch

public class cu {

    public static void main(String[] args) throws InterruptedException {
        int n = 100;
        CountDownLatch count = new CountDownLatch(2);
        AddTest test1 = new AddTest(0, n / 2, count);
        AddTest test2 = new AddTest((n / 2) + 1, n, count);
        Thread t1 = new Thread(test1, "t1");
        Thread t2 = new Thread(test2, "t2");
        t1.start();
        t2.start();
        count.await();
        System.out.println("结果是:"+test1.getRes()+test2.getRes());
    }
}

class AddTest implements Runnable{
    private int begin;
    private int end;
    private int res;
    private CountDownLatch count;

    public AddTest(int begin, int end,CountDownLatch countDownLatch) {
        this.begin = begin;
        this.end = end;
        this.count = countDownLatch;
    }
    @Override
    public void run() {
        int sum = 0;
        for (int i = begin; i <= end; i++) {
            sum+=i;
        }
        res = sum;
        count.countDown();  //每次调用一个线程
    }
    public int getRes(){
        return res;
    }
}

第六题

思路:创建两个线程,分别计算,利用countdownlunch,进行线程同步,然后返回

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值