一次使用两个线程打印字母和数字

时间:2018-10-12 20:05:32

标签: java multithreading concurrency thread-safety

我正在研究以下面试问题,我需要使用两个线程来打印字母和数字。一个打印字母(a,b,c ... z),其他打印数字(1,2,3 .... 26)。现在,我必须以一种这样的方式来实现它,即输出应该是:

a
1
b
2
...
...
z
26

所以我想出了下面的代码,没有同步,但是由于某种原因,它没有打印出最后一个字母z

class Output {
  private static final int MAX = 26;
  private static int count = 1;
  private static final Queue<Character> queue = new LinkedList<>(Arrays.asList(new Character[] {
      'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
      's', 't', 'u', 'v', 'w', 'x', 'y', 'z'}));
  private boolean isAlphabet = true;

  public void printAlphabet() {
    while (true) {
      if (count > MAX)
        break;
      if (!isAlphabet) {
        System.err.println(Thread.currentThread().getName() + " : " + queue.remove());
        isAlphabet = true;
      }
    }
  }

  public void printNumber() {
    while (true) {
      if (count > MAX)
        break;
      if (isAlphabet) {
        System.err.println(Thread.currentThread().getName() + " : " + count++);
        isAlphabet = false;
      }
    }
  }
}


public class PrintAlphabetNumber {
  public static void main(String[] args) {
    Output p = new Output();
    Thread t1 = new Thread(() -> p.printAlphabet());
    t1.setName("Alphabet");
    Thread t2 = new Thread(() -> p.printNumber());
    t2.setName("Number");

    t1.start();
    t2.start();
  }
}

以上代码中是否存在任何问题?同样从同步角度看,它看起来好还是不好?

2 个答案:

答案 0 :(得分:5)

  

由于某种原因,它没有打印最后一个字母z

您在count > MAX(在最后一个数字之后为true)时中止。

在最后一个数字之后,您应该打印出最后一个字母,但是现在count > MAX已经停止了。

  

从同步角度看,它看起来好不好?

不,这看起来不太好。

您正在使用自旋锁。这是非常低效的,因为无论是否有工作要做,这两个循环都会不断使用100%CPU。也不能保证使用非易失性锁变量。

经典的Java解决方案将使用wait()/notify()

答案 1 :(得分:1)

就像他们说的那样,

并不是很好的代码,但是此代码的问题在于,您获得了if条件。

public void printAlphabet() {
    while (true) {
        if (count > MAX)
            break;
        if (isAlphabet) {// this was !isAlphabet
            System.err.println(Thread.currentThread().getName() + " : " + queue.remove());
            isAlphabet = false;//also here
        }
    }
}

public void printNumber() {
    while (true) {
        if (count > MAX)
            break;
        if (!isAlphabet) {// this was isAlphabet
            System.err.println(Thread.currentThread().getName() + " : " + count++);
            isAlphabet = true;//also here
        }
    }
}