【问题标题】:Using multiple threads to print statements sequentially使用多个线程顺序打印语句
【发布时间】:2015-06-09 15:11:02
【问题描述】:

我正在尝试使用三个线程打印从 1 到 10 的数字。线程 1 打印 1,2 打印 2,3 打印 3,线程 1 再次打印 4,依此类推。

我创建了一个共享打印机资源来帮助这些线程打印数字。但我很困惑,我怎样才能让所有线程都看到这个数字。

问题是每个线程都看到自己的数字副本,而我需要所有线程共享相同的数字。

我正在尝试创建此示例以用于学习目的。我在 SO 上看到了其他有同样问题的页面,但我无法理解这个概念。

感谢任何帮助。

这个例子与我所做的有什么不同? Printing Even and Odd using two Threads in Java

public class PrintAlternateNumber {


    public static void main(String args[]) {

        SharedPrinter printer = new SharedPrinter();

        Thread t1 = new Thread(new myRunnable2(printer,10,1),"1");
        Thread t2 = new Thread(new myRunnable2(printer,10,2),"2");
        Thread t3 = new Thread(new myRunnable2(printer,10,3),"3");

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

class myRunnable2 implements Runnable {

    int max;
    SharedPrinter printer;
    int threadNumber;

    int number=1;

    myRunnable2(SharedPrinter printer,int max,int threadNumber) {
        this.max=max;
        this.printer=printer;
        this.threadNumber=threadNumber;
    }

    @Override
    public void run() {
        System.out.println(" The thread that just entered run "+ Thread.currentThread().getName());     
        for(int i =1;i<max;i++){
            try {
                printer.print(i,threadNumber);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }


}


class SharedPrinter {

    boolean canPrintFlag=false;


    public synchronized void print(int number,int threadNumber) throws InterruptedException{

        if(number%3==threadNumber) {
            canPrintFlag=true;
        }

        while(!canPrintFlag)
        {
            System.out.println(Thread.currentThread().getName() + " is waiting as it cannot print " + number);
            wait();


        }
        System.out.println(Thread.currentThread().getName()+" printed "+number);
        canPrintFlag=false;
        notifyAll();



    }
}

//output
 //The thread that just entered run 2
// The thread that just entered run 3
 //The thread that just entered run 1
//3 is waiting as it cannot print 1
//1 printed 1
//1 is waiting as it cannot print 2
//3 is waiting as it cannot print 1
//2 is waiting as it cannot print 1

技术二

它仍然不完整,但我很接近

输出

0由0印刷 2印刷者2 1印刷者1

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

class AlternateNumber {

    public static void main(String args[]) {

        printerHell ph = new printerHell();
        BlockingQueue<Integer> queue = new ArrayBlockingQueue<Integer>(10);     
        for(int i=0;i<10;i++)
        {
            queue.add(i);
        }

        Thread t1 = new Thread(new myRunnableHell(queue,0,ph),"0");
        Thread t2 = new Thread(new myRunnableHell(queue,1,ph),"1");
        Thread t3 = new Thread(new myRunnableHell(queue,2,ph),"2");

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

}

class myRunnableHell implements Runnable {

    BlockingQueue<Integer> queue;   
    int threadNumber;
    printerHell ph;

    myRunnableHell(BlockingQueue<Integer> queue, int threadNumber,printerHell ph) {

        this.queue=queue;       
        this.threadNumber=threadNumber;
        this.ph=ph;
    };

    int currentNumber;

    @Override
    public void run() {

        for(int i=0;i<queue.size();i++)
        {
            currentNumber=queue.remove();

            if(threadNumber%3==currentNumber) 
            {
                ph.print(currentNumber);
            }   

        }   

    }   

}

class printerHell {

    public synchronized void print(int Number)
    {
        System.out.println(Number + "printed by" + Thread.currentThread().getName());
    }


}

【问题讨论】:

  • 请将您的标题更改为描述问题的内容。暂时没用。
  • 另外,查看 Ping-Pong 多线程示例。这是同一个问题。
  • @SotiriosDelimanolis :我更新了标题,希望现在看起来不错。我不明白如何将此号码作为共享资源打印?似乎每个线程都看到了自己的副本。你能在我做错的地方给我一些启发吗?我正在努力解决这个问题,花了大约 4-5 个小时但没有到达任何地方:(

标签: java multithreading concurrency java.util.concurrent


【解决方案1】:

请在此处查看我的解决方案..

使用简单的等待/通知 https://stackoverflow.com/a/31668619/1044396

使用循环障碍: https://stackoverflow.com/a/23752952/1044396

关于“它与偶数/奇数线程问题有何不同”的查询。 --> 几乎是一样的...而不是保持两个状态有一个状态来调用第三个线程,所以我相信,这可以扩展任意数量的线程。

编辑:

当您希望有“n”个线程按顺序执行工作时,您可以查看此方法。(而不是使用不同的类 t1、t2、t3 等)

https://codereview.stackexchange.com/a/98305/78940

编辑2: 上面的解决方案再次复制这里的代码

我尝试使用单个类 'Thrd' 来解决问题,该类以其起始编号进行初始化。

ThreadConfig 类,作为您要创建的线程总数的大小。

状态类,维护前一个线程的状态。(保持顺序)

给你..(请查看并让我知道你的观点)

编辑: 它是如何工作的-->

当一个线程 Tx 有机会执行时.. 它会用 x 设置状态变量的状态。因此,一旦状态更新,下一个线程(Tx+1)等待将有机会。这样您就可以保持线程的顺序。

我希望我能够解释代码。请运行它并查看或让我知道有关以下代码的任何特定查询

1) 包 com.kalyan.concurrency;

    public class ThreadConfig {

        public static final int size = 5;

    }

2) 包 com.kalyan.concurrency;

    public class State {

      private volatile int state ;

        public State() {
            this.state =3;
        }

        public State(int state) {
            this.state = state;
        }

        public  int getState() {
            return state;
        }

        public  void setState(int state) {
            this.state = state;
        }


    }

3) 包 com.kalyan.concurrency;

        public class Thrd implements Runnable {

            int i ;
            int name;
            int prevThread;
            State s;
            public Thrd(int i,State s) {
                this.i=i;
                this.name=i;
                this.prevThread=i-1;
                if(prevThread == 0) prevThread=ThreadConfig.size;
                this.s=s;
            }

            @Override
            public void run() {


                while(i<50)
                {
                    synchronized(s)
                      {
                          while(s.getState() != prevThread)
                          {


                                  try {
                                    s.wait();
                                } catch (InterruptedException e) {
                                    // TODO Auto-generated catch block
                                    e.printStackTrace();
                                }
                              }

                          } 

                              synchronized(s)
                              {
                               //if(s.getState() ==3)

                              if(s.getState()==prevThread)
                               System.out.println("t"+ name+ i);
                               s.setState(name);
                                   i = i +ThreadConfig.size ;
                              s.notifyAll();


                             }   
                }

            }

        }

4) 包 com.kalyan.concurrency;

        public class T1t2t3 {
        public static void main(String[] args) {

            State s = new State(ThreadConfig.size);


            for(int i=1;i<=ThreadConfig.size;i++)
            {
                Thread T = new Thread(new Thrd(i,s));   
                T.start();

            }



        }
        }

输出:

 t11
 t22
 t33
 t44
 t55
 t16
 t27
 t38
 t49
 t510
 t111
 t212
 t313
 t414
 t515
 t116..............

【讨论】:

    【解决方案2】:

    我希望我理解你的意思,但是在 java 中有一些主要的“特性”可以让一个变量在线程之间共享:

    • 易失性关键字

      易失性整数 = 1;

    • AtomicInteger(标准 java 类 -> 无库)

      AtomicInteger number = new AtomicInteger(1);

    这两种技术应该都可以做你想做的,但是我没有使用它的经验,我只是偶然发现了这个词,不知道它是什么意思并做了一些挖掘。

    一些需要阅读的东西:;)

    volatile 为 java 解释 --> http://java.dzone.com/articles/java-volatile-keyword-0

    更好的解释(带有图像!!)但对于 c#(仍然是相同的用法)--> http://igoro.com/archive/volatile-keyword-in-c-memory-model-explained/

    以及 AtomicInteger 一些用法的链接 --> https://stackoverflow.com/a/4818753/4986655

    我希望我能帮助你,或者至少让你朝着正确的方向前进 :)
    - 超级模糊

    【讨论】:

    • Volatile 不会导致变量在线程之间共享。
    • 我希望不使用 AtomicInteger 也能做到
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多