【问题标题】:Can I reuse the threads for all the iterations of the for loop here?我可以在这里为 for 循环的所有迭代重用线程吗?
【发布时间】:2017-11-26 03:02:56
【问题描述】:

来自http://www.siddhartha.ac.in/downloads/JP_Lab_Record2.pdf。

编写实现多线程应用程序的 Java 程序,该应用程序具有 三个线程。第一个线程每秒生成随机整数 如果值是偶数,第二个线程计算数字的平方 和打印。如果值为奇数,第三个线程将打印该值 数的立方。

import java.util.*;
class even implements Runnable
{
    public int x;
    public even(int x)
    {
        this.x = x;
    }
    public void run()
    {
        System.out.println("New Thread "+ x +" is EVEN and Square of " + x + " is: " + x * x);
    }
}
class odd implements Runnable
{
    public int x;
    public odd(int x)
    {
        this.x = x;
    }
    public void run()
    {
        System.out.println("New Thread "+ x +" is ODD and Cube of " + x + " is: " + x * x * x);
    }
}
class A extends Thread
{
    public void run()
    {
        int num = 0;
        Random r = new Random();
        try
            {
                for (int i = 0; i < 5; i++)
                    {
                        num = r.nextInt(100);
                        System.out.println("Main Thread and Generated Number is " + num);
                        if (num % 2 == 0)
                            {
                              Thread t1 = new Thread(new even(num));
              t1.start();
                            } else {
                            Thread t2 = new Thread(new odd(num));
                            t2.start();
          }
                        Thread.sleep(1000);
          System.out.println("--------------------------------------");
                    }
            }
        catch (Exception ex)
            {
                System.out.println(ex.getMessage());
            }
    }
}
public class JavaProgram5
{
    public static void main(String[] args)
    {
        A a = new A();
        a.start();
    }
}

在main 方法中,对于for 循环的每次迭代,都会创建两个新线程。是否可以在 for 循环的所有迭代中重用这两个线程?

谢谢。

【问题讨论】:

  • 你为什么要用多个线程来做这个?您可能会遇到很多同步问题。为什么不让一个线程打印值?
  • @FredK 这听起来像是一个旨在创建同步问题的作业
  • @John 这是一项任务,但我的想法超出了任务范围。
  • 按照惯例,类名以大写字母开头。
  • 本课的主题是什么?例如是生产者和消费者吗?因为这确实是你应该在这里做的。

标签: java multithreading


【解决方案1】:

你不能重启一个线程,见:https://docs.oracle.com/javase/8/docs/api/java/lang/Thread.html#start--

多次启动一个线程是不合法的

但是,您可能想看看使用ThreadPool。见:https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ThreadPoolExecutor.html

【讨论】:

    【解决方案2】:

    线程不能按照您的想法重复使用。您正在做的实际上是每次生成一个数字时都会启动一个新线程。到那时,您可能根本就没有单独的线程来进行计算。

    问题的潜台词似乎表明您始终在运行三个线程。这使得你的问题本质上是一个有两个消费者情况的生产者​​。唯一的问题是消费者必须明智地采取行动,并且只获取他们需要的数据。

    您的生成器代码在正确的轨道上,处理代码也是如此。需要发生的主要变化是,生产者应该notify(实际上是notifyAll)运行Even和Odd的线程,而不是启动一个新线程。

    由于我们每秒生产一个项目,因此您实际上并不需要适当的队列。单个Integer 对象足以容纳未使用的数字。如果即使在相对较旧的架构上处理时间也超过一秒,您还有其他问题需要担心。使用Integer 而不是int 的原因是您需要能够向等待线程发出该对象已被使用的信号:在这种情况下,返回null 似乎是一种非常简单的方法。

    class Producer implements Runnable, IntConsumer
    {
        private Integer buffer = null;
    
        public void run()
        {
            new Random().ints().forEach(this);
        }
    
        public void accept(int i)
        {
            synchronized(this) {
                this.buffer = i;
                this.notifyAll();
            }
            try {
                Thread.sleep(1000L);
            } catch(InterruptedException ie) {
                throw new RuntimeException("Producer interrupted!");
            }
        }
    
        public Integer peek()
        {
            return this.buffer;
        }
    
        public synchronized Integer get()
        {
            Integer i = peek();
            this.buffer = null;
            return i;
        }
    }
    

    请注意,生成的整数被放置在可以通过peek 和get 访问的字段中。生成代码锁定生产者对象,get 也是如此,它会清除缓冲区。这样可以确保一次只有一个实体可以修改该值。

    通常消费者和生产者将通过共享堆栈或队​​列对象或类似的东西进行通信。同步也由队列完成,如LinkedBlockingQueue 或ArrayBlockingQueue。在这个简单的例子中,生产者实现了队列功能,因此消费者必须知道生产者。

    消费者线程有很多共同的功能。他们都必须等待生产者的通知,获取锁,检查下一个对象是否未被消费并且属于他们,然后消费它或继续等待。请注意,整个 check-then-get 操作应该是原子的以避免错误。所有这些都可以很容易地在基类中编码。此类将具有检查和处理数字的抽象方法:

    public abstract class Consumer implements Runnable
    {
        private final Producer producer;
    
        public Consumer(Producer producer)
        {
            this.producer = producer;
        }
    
        public void run()
        {
            while(true) {
                synchronized(this.producer) {
                    Integer i = this.producer.peek();
                    if(i != null && check(i)) {
                        this.producer.get();
                        process(i);
                    }
                    try {
                        this.producer.wait();
                    } catch(InterruptedException ie) {
                        throw new RuntimeException("Consumer interrupted!");
                    }
                }
            }
        }
    
        public abstract boolean check(int i);
    
        public abstract void process(int i);
    }
    

    具体实现检查是否输入的数字的奇偶性,并处理它们适合的数字。请注意,我让check 和process 接受int 而不是Integer,以强调检查生产者是否为空不是他们的责任。

    public class Even extends Consumer
    {
        public Even(Producer producer)
        {
            super(producer);
        }
    
        public boolean check(int i)
        {
            return (i % 2) == 0;
        }
    
        public void process(int i)
        {
            System.out.println("x=" + i + "; x^2=" + (i * i));
        }
    }
    

    public class Odd extends Consumer
    {
        public Odd(Producer producer)
        {
            super(producer);
        }
    
        public boolean check(int i)
        {
            return (i % 2) != 0;
        }
    
        public void process(int i)
        {
            System.out.println("x=" + i + "; x^3=" + (i * i * i));
        }
    }
    

    最后,包含main 方法的驱动程序将所有这些联系在一起:

    public class Driver
    {
        public static void main(String[] args)
        {
            Producer prod = new Producer();
            new Thread(new Even(prod)).start();
            new Thread(new Odd(prod)).start();
            new Thread(prod).start();
        }
    }
    

    如果您在主线程提前退出时遇到问题,请强制 main 等待生产者(永远)完成,例如:

    Thread t = new Thread(prod);
    t.start();
    t.join();
    

    代码将产生如下输出,每秒一次,直到您按下Ctrl+C(至少在 Linux 上):

    x=966307133; x^3=-1676528219
    x=1271569805; x^3=-1481001707
    x=456385150; x^2=-1701399036
    x=-474801821; x^3=-813682373
    x=-1046547765; x^3=927976307
    x=-148577454; x^2=-185956796
    x=-14905035; x^3=-1126539123
    x=2071820769; x^3=-1426032223
    x=1075272421; x^3=1952259101
    x=-895041093; x^3=-978791741
    x=-2054472224; x^2=3441664
    ...
    

    【讨论】:

      【解决方案3】:

      使用固定线程池。它会重用线程

                  import java.util.Random;
                  import java.util.concurrent.ExecutorService;
                  import java.util.concurrent.Executors;
                  import java.util.concurrent.TimeUnit;
      
      
                  public class MainClass {
      
                      public static void main(String[] args){
      
      
                            A a = new A();
                              a.start();
      
                      }
      
                  }
      
                  class A extends Thread
                  {
                      public void run()
                      {
      
                          ExecutorService executorService = Executors.newFixedThreadPool(2);
                          int num = 0;
                          Random r = new Random();
                          try
                              {
                                  for (int i = 0; i < 5; i++)
                                      {
                                          num = r.nextInt(100);
                                          System.out.println("Main Thread and Generated Number is " + num);
                                          if (num % 2 == 0)
                                              {
                                               executorService.submit(new even(num));
      
                                              } else {
                                                   executorService.submit(new odd(num));
      
                            }
                                          Thread.sleep(1000);
                            System.out.println("--------------------------------------");
                                      }
                              }
                          catch (Exception ex)
                              {
                                  System.out.println(ex.getMessage());
                              }
                       finally {
                          executorService.shutdown();
                      }
                      try {
                          executorService.awaitTermination(1, TimeUnit.HOURS);
                      } catch (InterruptedException e) {
                          e.printStackTrace();
                      }
                      }
                  }
      
                  class even implements Runnable
                  {
                      public int x;
                      public even(int x)
                      {
                          this.x = x;
                      }
                      public void run()
                      {
                          System.out.println("New Thread "+ x +" is EVEN and Square of " + x + " is: " + x * x);
                      }
                  }
                  class odd implements Runnable
                  {
                      public int x;
                      public odd(int x)
                      {
                          this.x = x;
                      }
                      public void run()
                      {
                          System.out.println("New Thread "+ x +" is ODD and 
                     Cube of " + x + " is: " + x * x * x);
                      }
                  }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-02-10
        • 1970-01-01
        • 1970-01-01
        • 2023-01-27
        • 1970-01-01
        • 1970-01-01
        • 2014-01-12
        • 2014-04-29
        相关资源
        最近更新 更多