一道基础的多线程题目

  之前把thread基础温习了一遍,然后想通过做一些题目来加深自己的印象,刚好大四找工作面试时被问到一道题目:A-Z,1-26,使用多线程打印出A1B2C3D4E5......这种,当时自己好像回答的并不好,于是今天重新写了一遍。

  首先我们需要新建两个类,一个用来打印A-Z,一个用来打印1-26。这里为了省略,我只打印了前面几个数字和字母。我们一步一步来。

public class PrintCharacter extends Thread {


    @Override
    public void run() {
        List<String> list = Arrays.asList("A", "B", "C", "D", "E");
        for (String str : list) {
            System.out.println(str);
        }
    }
}
public class PrintNumber extends Thread {

    @Override
    public void run() {
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
        for (Integer i : list) {
            System.out.println(i);
        }
    }
}
public static void main(String[] args) {
        PrintCharacter pc = new PrintCharacter();
        PrintNumber pn = new PrintNumber();
        pc.setPriority(10);
        pn.setPriority(1);
        pc.start();
        pn.start();
    }

  这里的代码比较简单,主线程开启了两个线程,并设置打印字母的线程的优先级为最高(网上说设置优先级并不能一定保证会先执行,但是我这里试验过很多次都是先打印字母的)。通过代码我们看出不出意外结果应该是ABCDE12345这样打印的。不符合题目。然后我想到了sleep()这个方法,他可以让线程休眠一定时间再进入就绪状态,那么理论上他是完全可以实现题目的效果的。

public class PrintCharacter extends Thread {


    @Override
    public void run() {
        List<String> list = Arrays.asList("A", "B", "C", "D", "E");
        for (String str : list) {
            try {
                System.out.println(str);
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
public class PrintNumber extends Thread {

    @Override
    public void run() {
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
        for (Integer i : list) {
            try {
                System.out.println(i);
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

  这里与上面代码的区别就是每次循环打印之后我让线程休眠0.5s,首先打印字母A和数字1,然后两个线程休眠0.5s,然后继续打印,直到循环结束。运行结果证明这种方法的确可行,但是这种方法只能说完成了题目要求的。他需要线程一直休眠。这种实现方法个人觉得可以帮助我们理解sleep()方法,但是并不好。这个时候我想到了另外的一种实现方法,那就是多线程中最常用的锁,通过锁来实现交替打印。在说这种方法之前我们再次说明wait()方法和notify()方法。

  wait()方法和notify()方法的使用前提都需要拿到锁,因此他们通常在同步代码块中使用。wait()方法会释放当前线程的锁,然后自身进入阻塞状态。notify()方法会唤醒一个正在阻塞状态的线程,然后他不会立即释放锁,而是等到执行完同步代码块中的内容,在释放锁。然后就是wait()方法和notify()方法的顺序不能错,即先执行wait()方法在执行notify()方法才能被唤醒。介绍完这两个方法,然后我们开始看代码。

public class PrintCharacter extends Thread {

    private Object lock;

    public PrintCharacter(Object lock) {
        this.lock = lock;
    }

    @Override
    public void run() {
        List<String> list = Arrays.asList("A", "B", "C", "D", "E");
        for (String str : list) {
            synchronized (lock) {
                try {
                    lock.notify();
                    System.out.println(str);
                    lock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
public class PrintNumber extends Thread {

    private Object lock;

    public PrintNumber(Object lock) {
        this.lock = lock;
    }

    @Override
    public void run() {
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
        for (Integer i : list) {
            synchronized (lock) {
                try {
                    lock.notify();
                    System.out.println(i);
                    lock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
    public static void main(String[] args) {
        Object lock = 0;
        PrintCharacter pc = new PrintCharacter(lock);
        PrintNumber pn = new PrintNumber(lock);
        pc.setPriority(10);
        pn.setPriority(1);
        pc.start();
        pn.start();
    }

  首先,我们分析一下代码,这两个线程都有一个lock对象,而且通过synchronized关键字保证这个对象不能同时被多个线程访问。然后在run()方法中,首先唤醒一个正在阻塞状态的线程,然后打印。然后让释放锁并让自身阻塞。主线程运行时执行两个子线程,首先执行打印字母的线程,他执行notify()方法,因为当前没有线程处于阻塞状态,所以不起作用,然后打印A,之后释放锁,并让自身阻塞。然后打印数字的线程获得锁开始执行,他执行notify()方法唤醒打印字母的线程,然后打印1,然后让自身阻塞,最后释放锁。这样一直循环。直到循环结束。

  这种方法看上去挺好的,但是实际上还是有问题的,问题就是当两个线程最后一次循环的时候打印数字线程会调用wait()方法令自身阻塞。然后导致程序无法结束,,,这样看起来问题好像更严重了。。。看来这道简单的多线程题目并不简单。下篇博客再来探讨这个题目。

猜你喜欢

转载自www.cnblogs.com/xslzjbra/p/9959579.html