Java 用两条线一次打印一个字母和数字
我正在做下面的面试问题,我需要用两个线程打印出字母和数字。一个打印字母表(a,b,c…z),另一个打印数字(1,2,3…26)。现在我必须以这样一种方式实现它,即输出应该是:Java 用两条线一次打印一个字母和数字,java,multithreading,concurrency,thread-safety,Java,Multithreading,Concurrency,Thread Safety,我正在做下面的面试问题,我需要用两个线程打印出字母和数字。一个打印字母表(a,b,c…z),另一个打印数字(1,2,3…26)。现在我必须以这样一种方式实现它,即输出应该是: a 1 b 2 ... ... z 26 因此,我提出了下面的代码1,没有同步,但出于某种原因,它没有打印最后一个字母,即z class Output { private static final int MAX = 26; private static int count = 1; private stat
a
1
b
2
...
...
z
26
因此,我提出了下面的代码1,没有同步,但出于某种原因,它没有打印最后一个字母,即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();
}
}
类输出{
专用静态最终int MAX=26;
私有静态整数计数=1;
private static final Queue Queue=new LinkedList(Arrays.asList)(新字符[]){
‘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’});
私有布尔值isAlphabet=true;
公共空白打印字母表(){
while(true){
如果(计数>最大值)
打破
如果(!isAlphabet){
System.err.println(Thread.currentThread().getName()+“:“+queue.remove());
isAlphabet=true;
}
}
}
公共无效打印编号(){
while(true){
如果(计数>最大值)
打破
如果(isAlphabet){
System.err.println(Thread.currentThread().getName()+“:”+count++);
isAlphabet=假;
}
}
}
}
公共类打印字母编号{
公共静态void main(字符串[]args){
输出p=新输出();
线程t1=新线程(()->p.printAlphabet());
t1.集合名(“字母表”);
线程t2=新线程(()->p.printNumber());
t2.设置名称(“编号”);
t1.start();
t2.start();
}
}
我上面的代码有什么问题吗?同样从同步的角度来看,它看起来好还是不好
出于某种原因,它没有打印最后一个字母,即z
当count>MAX
时中止,这在最后一个数字后为真
在最后一个数字之后,您应该打印最后一个字母,但是现在count>MAX
,所以它已经停止了
从同步的角度来看,它看起来好还是不好
不,这看起来不太好
您正在使用自旋锁。这是非常低效的,因为无论是否有工作要做,两个循环都会持续使用100%的CPU。它也不能保证使用非易失性锁变量
经典的Java解决方案将使用wait()/notify()
出于某种原因,它没有打印最后一个字母,即z
当count>MAX
时中止,这在最后一个数字后为真
在最后一个数字之后,您应该打印最后一个字母,但是现在count>MAX
,所以它已经停止了
从同步的角度来看,它看起来好还是不好
不,这看起来不太好
您正在使用自旋锁。这是非常低效的,因为无论是否有工作要做,两个循环都会持续使用100%的CPU。它也不能保证使用非易失性锁变量
经典的Java解决方案将使用
wait()/notify()
,就像他们说的那样,这不是一个好的代码,但是这段代码的问题是您将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
}
}
}
就像他们说的,这不是一个很好的代码,但是这段代码的问题是你得到了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
}
}
}
isAlphabet
应声明为volatile
。您也可以为此使用信号量。您不允许使用锁吗?我也可以使用锁,但在这个特定场景中,我怀疑我们是否需要同步,但我也可以使用同步。@Ivan为什么必须声明为volatile。我知道我们在线程之间共享数据,但您不认为对于这个特殊问题,我们可能不需要同步吗?两个线程都在读取和写入共享变量。它应该同步,以便一个线程所做的更改对另一个线程100%可见isAlphabet
应该声明为volatile
。您也可以为此使用信号量。您不允许使用锁吗?我也可以使用锁,但在这个特定场景中,我怀疑我们是否需要同步,但我也可以使用同步。@Ivan为什么必须声明为volatile。我知道我们在线程之间共享数据,但您不认为对于这个特殊问题,我们可能不需要同步吗?两个线程都在读取和写入共享变量。它应该同步,以便一个线程所做的更改现在对anotherMake sense 100%可见。我怎样才能解决这个问题?我认为在这个特定场景中,我们根本不需要锁,但我也愿意使用锁解决方案。如果您有更好或更有效的方法,请让我知道在最简单的情况下,您可以使您的方法同步,并在您更改isAlphabet
和wait()
时添加notify()
,无论何时检查它,它都不是您想要的值。@zapl获得了它。。您能否在此解决方案的基础上添加答案。另外,如果您能为此添加Java7解决方案,这将非常好,它将帮助我更好地理解。我怎样才能解决这个问题?我认为在这个特定场景中,我们根本不需要锁,但我也愿意使用锁解决方案。如果您有更好或更有效的方法,请让我知道在最简单的情况下,您可以使您的方法同步,并在您更改isAlphabet
和wait()
时添加notify()
,无论何时检查它,它都不是您想要的值。@zapl获得了它。。您能否在此解决方案的基础上添加答案。另外,如果您能为此添加Java7解决方案,这将非常棒,它将帮助我更好地理解。