Java 线程:如何一次使用两个线程打印字母和数字

Posted

技术标签:

【中文标题】Java 线程:如何一次使用两个线程打印字母和数字【英文标题】:Java Threads: How to print alphabets and numbers using two threads one at a time 【发布时间】:2018-01-25 18:56:03 【问题描述】:

我正在尝试使用 java 中的线程。虽然我知道线程输出是不可预测的,但是想知道是否有办法做到这一点。

我必须实现两个线程,一个打印字母(a,b,c...z),另一个打印数字(1,2,3....26)。必须以输出应为a,1,b,2,c,3,d,4......z,26 的方式实现它。下面是我的代码,但它没有提供所需的输出。

public class ThreadsExample 

  public static void main(String[] args) 
    Runnable r = new Runnable1();
    Thread t = new Thread(r);
    Runnable r2 = new Runnable2();
    Thread t2 = new Thread(r2);
    t.start();
    t2.start();
  


class Runnable2 implements Runnable
  public void run()
    for(char i='a';i<='z';i++) 
        System.out.print(i+",");
    
  


 class Runnable1 implements Runnable
  public void run()
    for(int i=1;i<=26;i++) 
       System.out.print(i+",");
    
 

我应该在代码中进行哪些调整以获得所需的输出? synchronization 对此有何帮助?或者在使用线程时真的有可能吗?

PS:这不是作业或练习。它的自我学习。

【问题讨论】:

【参考方案1】:

这是可能的。你需要很好地同步它。

接近伪代码

查询一些(同步的)状态 state 将告诉是否允许使用 nums 或 chars

如果状态允许 char 并且调用者将放置 chars,现在就执行并更改状态并唤醒等待线程

如果没有,请等待

如果状态允许数字并且调用者将输入数字,现在就做并改变状态并唤醒等待线程

如果没有,请等待

Java 代码

public class ThreadsExample 
  public static ThreadsExample output = new ThreadsExample ();

  public static void main(String[] args) 
    Runnable r = new Runnable1();
    Thread t = new Thread(r);
    Runnable r2 = new Runnable2();
    Thread t2 = new Thread(r2);
    t.start();
    t2.start();
  

  private Object syncher = new Object ();  // we use an explicit synch Object, you could use annotation on methods, too. like ABHISHEK did.
             // explicit allows to deal with more complex situations, especially you could have more the one locking Object
  private int state = 0; // 0 allows chars, 1 allows ints

  public void print (char pChar) 
    synchronized (syncher)       // prevent the other print to access state
        while (true) 
            if (state == 0)      // char are allowed
                System.out.print(pChar + ","); // print it
                state = 1;        // now allow ints
                syncher.notify(); // wake up all waiting threads
                return;
             else               // not allowed for now
                try 
                    syncher.wait();  // wait on wake up
                 catch (InterruptedException e) 
                
            
        
    
  

  public void print (int pInt) 
    synchronized (syncher) 
        while (true) 
            if (state == 1) 
                System.out.print(pInt + ",");
                state = 0;
                syncher.notify();
                return;
             else 
                try 
                    syncher.wait();
                 catch (InterruptedException e) 
                
            
        
     
  


class Runnable2 implements Runnable
  public void run()
    for(char i='a';i<='z';i++) 
        ThreadsExample.output.print(i);
    
  


 class Runnable1 implements Runnable
  public void run()
    for(int i=1;i<=26;i++) 
        ThreadsExample.output.print(i);
    
 

输出

a,1,b,2,c,3,d,4,e,5,f,6,g,7,h,8,i,9,j,10,k,11,l,12 ,m,13,n,14,o,15,p,16,q,17,r,18,s,19,t,20,u,21,v,22,w,23,x,24,y ,25,z,26,

【讨论】:

现在查看代码和其他链接有了更好的理解。谢谢。【参考方案2】:

线程的整个概念:它代表了一个“活动流”,它独立于其他线程执行代码。

在您的情况下,您希望这两个线程“步调一致”。线程 A 执行一步,然后是线程 B,然后是 A,然后是 B。

为了到达那里,两个线程需要“同步”一些东西——换句话说:A 在完成其步骤后向 B 发送一个信号——而 B 必须等待信号。然后 B 做它的事,向 A 发出信号,...

对于初学者来说,一个简单的布尔值就可以了。一个线程将其设置为 true,另一个设置为 false(以指示它何时完成了它的步骤)。然后线程等待布尔值再次切换。

当你打算学习东西时,我会从那里开始尝试。如果你想走弯路,例如看here。 This 也可能有所帮助。

【讨论】:

感谢您的解释。链接清除了同步周围的空气。【参考方案3】:

这里是代码:: 您需要创建 2 个线程并正确实现等待和通知方法,您也可以参考“Create two threads, one display odd & other even numbers”以获得答案。

    public class ThreadClass 
    volatile int i = 1;
    volatile Character c = 'a';
    volatile boolean state = true;

    synchronized public void printAlphabet() 
        try 
            while (!state) 
                wait();
            
         catch (InterruptedException e) 
            e.printStackTrace();
        
        System.out.println(Thread.currentThread().getName() + " " +c);
        state = false;
        c++;
        notifyAll();
    
    synchronized public void printNumbers() 
        try 
            while (state) 
                wait();
            
         catch (InterruptedException e) 
            e.printStackTrace();
        
        System.out.println(Thread.currentThread().getName() + " " + i);
        state = true;
        i++;
        notifyAll();
    
    public static void main(String[] args) 
        ThreadClass threadClass = new ThreadClass();
        Thread t1 = new Thread() 
            int k = 0;
            @Override
            public void run() 
                while (k < 26) 
                    threadClass.printAlphabet();
                    k++;
                
            
        ;
        t1.setName("Thread1");
        Thread t2 = new Thread() 
            int j = 0;

            @Override
            public void run() 
                while (j < 26) 
                    threadClass.printNumbers();
                    j++;
                
            
        ;
        t2.setName("Thread2");

        t1.start();

        t2.start();
    

【讨论】:

【参考方案4】:

您的线程同时运行。但不是你想要的方式,如上所述。您将看到来自线程 1 的数据块,然后是来自线程 2 的数据块;这是因为线程调度。线程 1 只是在线程 2 之前将其输出排队。

要测试这个理论,例如将输出增加到 1000 条记录,因为字母表和 26 个数字并没有这么大。

通过这样做,您将看到这些数据“块”。有一种方法可以执行您提到的操作,但不建议这样做,因为这不是在演示线程的实际工作方式,而是您强制它以这种方式工作。

【讨论】:

【参考方案5】:

用更少的代码:

class MyRunnable implements Runnable 
    private static int n = 1;
    private static char c = 'a';

    public void run() 
        for (int i = 1; i <= 26; i++) 
            synchronized (this) 
                try 
                    notifyAll();
                    if (Thread.currentThread().getName().equals("A")) 
                        System.out.print(c + ",");
                        c++;
                     else 
                        System.out.print(n + ",");
                        n++;
                    
                    if (i != 26) 
                        wait();
                    
                 catch (InterruptedException e) 
                    e.printStackTrace();
                
            

        
    


public class PrintAlphabetNumberJob 

    public static void main(String[] args) throws InterruptedException 
        MyRunnable r = new MyRunnable();
        Thread tAlphabet = new Thread(r, "A");
        Thread tNumber = new Thread(r, "N");
        tAlphabet.start();
        Thread.sleep(100);
        tNumber.start();
    


【讨论】:

以上是关于Java 线程:如何一次使用两个线程打印字母和数字的主要内容,如果未能解决你的问题,请参考以下文章

写两个线程,交替打印数字和字母,一个线程打印 1~26,另一个线程打印字母 A-Z

一个java多线程面试题

java多线程轮流打印数字字母案例代码

经典多线程问题-轮流打印字母和数字

[******] java多线程连续打印abc

Java n个线程轮流打印数字的问题