多线程笔试题目记载

266 阅读1分钟

建立三个线程A、B、C, A线程打印10次字母A, B线程打印10次字母B, C线程打印10次字母C,但是要求三个线程同时运行, 并且实现交替打印,即按照ABCABCABC的顺序打印

方法1 wait notify 三个线程执行的顺序是:A打印前一定要是null("")或者C, B打印前一定要是A, C打印前一定要是A。

如何做到呢?让三个线程竞争同一个锁,获取到锁的那个线程才有机会执行打印动作,在执行打印动作之前需要根据规则判断能不能打印,能则打印,不能则释放锁,通知其他线程竞争。

代码如下

/**
 * @description:
 * @author: lkb
 * @create: 2021/9/5
 */
public class ThreadTest {

    private volatile String flag = "C";

    private synchronized void setFlag(String flag){
        this.flag = flag;
        System.out.println(Thread.currentThread().getName()+" print " + flag);
    }

    private String getFlag(){
        return this.flag;
    }


    class PrintThread extends Thread{
        private String oldFlag;
        private String newFlag;
        private Object lock;
        public PrintThread(String threadName, String oldFlag, String newFlag, Object lock){
            this.oldFlag = oldFlag;
            this.newFlag = newFlag;
            this.lock = lock;
            this.setName(threadName);
        }

        @Override
        public void run() {
            synchronized (lock){
                for(int i=0;i<10;){
                    if(StringUtils.equals(getFlag(), oldFlag)){
                        setFlag(newFlag);
                        i++;
                        lock.notifyAll();
                    }else{
                        try {
                            lock.wait();
                        }catch (InterruptedException e){
                            System.out.println(e);
                        }
                    }
                }
            }
        }
    }

    public static void main(String[] args) {
        ThreadTest threadTest = new ThreadTest();
        PrintThread printThreadA = threadTest.new PrintThread("ThreadA", "C","A", threadTest.flag);
        PrintThread printThreadB = threadTest.new PrintThread("ThreadB", "A","B", threadTest.flag);
        PrintThread printThreadC = threadTest.new PrintThread("ThreadC", "B","C", threadTest.flag);
        printThreadA.start();
        printThreadB.start();
        printThreadC.start();
    }
}

方法二 LockSupport.park() / LockSupport.unpark()

这个是抄的网上的。原理就是 LockSupport.unpark(Thread) 可以指定唤醒某个线程,park的作用有点类似wait。

/**
 * @description:
 * @author: lkb
 * @create: 2021/9/5
 */
public class ThreadTest {

    static Thread A, B,C;

    public static void main(String[] args) {
        A = new Thread(()->{
            for(int i = 0; i < 10; i++){
                LockSupport.park();
                System.out.println("A");
                LockSupport.unpark(B);
            }
        });

        B = new Thread(()->{
            for(int i = 0; i < 10; i++){
                LockSupport.park();
                System.out.println("B");
                LockSupport.unpark(C);
            }
        });

        C = new Thread(()->{
            for(int i = 0; i < 10; i++){
                LockSupport.unpark(A);
                LockSupport.park();
                System.out.println("C");
            }
        });

        A.start();
        B.start();
        C.start();

    }

方法三 ReentrantLock 和 Condition

原理和 wait notify 差不多

/**
 * @description:
 * @author: lkb
 * @create: 2021/9/5
 */
public class ThreadTest {


    private String stateFlag = "C";

    class PrintThread extends Thread{
        private Lock lock;
        private Condition condition;
        private String pre;
        private String curr;
        public PrintThread(Lock lock, Condition condition, String pre, String curr){
            this.lock = lock;
            this.condition = condition;
            this.pre = pre;
            this.curr = curr;
        }

        @Override
        public void run(){
            try {
                lock.lock();
                for(int i=0;i<10;i++){
                    while(!stateFlag.equals(pre)){
                        condition.await();
                    }

                    stateFlag = curr;
                    System.out.println(stateFlag);
                    condition.signalAll();
                }
            }catch (InterruptedException e){
                e.printStackTrace();
            }finally {
                lock.unlock();
            }
        }
    }


    public static void main(String[] args) {
        ThreadTest threadTest = new ThreadTest();
        Lock lock = new ReentrantLock();
        Condition condition = lock.newCondition();
        PrintThread printThreadA = threadTest.new PrintThread(lock, condition, "C", "A");
        PrintThread printThreadB = threadTest.new PrintThread(lock, condition, "A", "B");
        PrintThread printThreadC = threadTest.new PrintThread(lock, condition, "B", "C");
        printThreadA.start();
        printThreadB.start();
        printThreadC.start();
    }
}

做饭,做一个汤要十分钟,做一个炒菜要十五分钟,要求两个线程分别做汤、做菜,每隔5分钟,每个线程汇报一下结果

这个用Callable去做。

/**
 * 做饭,做一个汤要十分钟,做一个炒菜要十五分钟
 * 要求两个线程分别做汤、做菜,每隔5分钟,每个线程汇报一下结果
 * @author: lkb
 * @create: 2021/9/5
 */
public class ThreadTest {

    class DoSoup implements Callable{
        @Override
        public Object call() throws Exception {
            Thread.sleep(10*1000);
            System.out.println("汤做好了");
            return "汤做好了";
        }
    }

    class DoCook implements Callable{
        @Override
        public Object call() throws Exception {
            Thread.sleep(15*1000);
            System.out.println("菜做好了");
            return "菜做好了";
        }
    }


    public static void main(String[] args) throws Exception{
        ThreadTest threadTest = new ThreadTest();
        FutureTask doSoupTask = new FutureTask(threadTest.new DoSoup());
        Thread threadSoup = new Thread(doSoupTask);
        FutureTask doCookTask = new FutureTask(threadTest.new DoCook());
        Thread threadCook = new Thread(doCookTask);

        threadSoup.start();
        threadCook.start();
        boolean allFinish = false;
        while (!allFinish){
            if(doCookTask.isDone() && doSoupTask.isDone()){
                break;
            }

            Thread.sleep(5*1000);

            if(!doCookTask.isDone()){
                System.out.println("做菜中...");
            }

            if(!doSoupTask.isDone()){
                System.out.println("做汤中...");
            }
        }
    }
}

十个运动员参加跑步比赛,信息部需要在赛后统计十个人的平均耗时

public class ThreadTest {

    public static void main(String[] args) throws Exception {
        CountDownLatch countDownLatch = new CountDownLatch(10);
        AtomicLong total = new AtomicLong(0);
        for(int i=0;i<10;i++){
            FutureTask<Long> runTask = new FutureTask<>(() -> {
                long time = RandomUtil.randomInt(20, 30) * 100L;
                Thread.sleep(time);
                System.out.println(Thread.currentThread().getName() + " run " +time);
                total.getAndAdd(time);
                countDownLatch.countDown();
                return time;
            });
            Thread runner = new Thread(runTask);
            runner.start();
        }

        countDownLatch.await();

        System.out.println("平均耗时 :" + total.get() / 10);
    }