【问题标题】:I want to print the fibonacci series using two threads. Like 1st number should be printed by 1st thread and then 2nd number by 2nd thread and so on我想使用两个线程打印斐波那契数列。比如第一个数字应该由第一个线程打印,然后第二个数字由第二个线程打印,依此类推
【发布时间】:2021-04-04 10:33:45
【问题描述】:

我希望斐波那契数列按线程打印,该系列的第一个数字应该由第一个线程打印,然后第二个数字由第二个线程打印,然后第三个由第一个线程打印,第四个由第二个线程打印,依此类推。

我通过使用数组(例如使用线程打印数组元素)尝试了此代码,但我无法在线程之间切换。

class Fibonacci{
    void printFibonacci() {
       int fibArray[] = new int[10];
       int a = 0;
       int b = 1;
       fibArray[0] = a;
       fibArray[1] = b;
       int c;
       for(int i=2;i<10;i++) {
           c = a+b;
           fibArray[i] = c;
           a = b;
           b = c;
       }
       for(int i=0;i<10;i++) {
        if(Integer.parseInt(Thread.currentThread().getName())%2==0 && (i%2==0))
        {
            System.out.println("Thread " +Thread.currentThread().getName()+" "+fibArray[i]);
            try{
                wait();
            }catch(Exception e) {}
        }
        else if(Integer.parseInt(Thread.currentThread().getName())%2!=0 && (i%2!=0))
        {
            System.out.println("Thread " +Thread.currentThread().getName()+" "+fibArray[i]);
        }
     }
   }
}

public class FibonacciUsingThread {

    public static void main(String[] args) throws Exception {
        Fibonacci f = new Fibonacci();
        Thread t1 = new Thread(()->
        {
            f.printFibonacci();
        });
        Thread t2 = new Thread(()->
        {
            f.printFibonacci();
        });
        t1.setName("0");
        t2.setName("1");
        t1.start();
        t1.join();
        t2.start();
    }
}

【问题讨论】:

    标签: java multithreading parallel-processing


    【解决方案1】:

    正如“@Live and Let Live”所指出的,在正确性方面,您的代码的主要问题是缺少 synchronized 子句,并在启动第二个线程之前调用了第一个线程的 join

    IMO 你可以通过首先分离一点关注点来稍微清理一下代码,即Fibonacci 类只负责计算给定数组的斐波那契:

    class Fibonacci{
        void getFibonacci(int[] fibArray) {
            int a = 0;
            int b = 1;
            fibArray[0] = a;
            fibArray[1] = b;
            int c;
            for(int i=2;i<fibArray.length;i++) {
                c = a+b;
                fibArray[i] = c;
                a = b;
                b = c;
            }
        }
    }
    

    通过这种方式,您可以使您的Fibonacci 类保持简洁,而无需任何与线程相关的代码。此外,getFibonacci 现在更抽象了;您可以像以前一样计算不止 10 个元素的 fib

    然后上课FibonacciUsingThread

    public class FibonacciUsingThread {
    
            public static void main(String[] args) throws Exception {
                int [] array_fib = new int[10];
                Fibonacci f = new Fibonacci();
                f.getFibonacci(array_fib);
                Thread t1 = new Thread(()->
                {
                    for(int i = 0; i < array_fib.length; i+=2)
                        System.out.println("Thread 1:" + array_fib[i]);
                });
                Thread t2 = new Thread(()->
                {
                    for(int i = 1; i < array_fib.length; i+=2)
                        System.out.println("Thread 2:" + array_fib[i]);
                });
                t1.start();
                t2.start();
                t1.join();
                t2.join();
            }
        }
    

    首先,您使用 main 线程计算斐波那契,让所有线程计算相同的东西是没有意义的。之后,您指定 Thread 1Thread 2 将分别打印偶数和奇数位置。

    除非这只是线程和同步的练习,否则使用线程来完成这种工作没有多大意义。在您的代码中,值得并行化的部分是斐波那契数本身的计算,而不是打印部分。

    前面显示的代码不会按顺序打印斐波那契数,因为您需要确保线程在遍历数组的每个元素后彼此等待。因此,您需要调整将由线程执行的代码,即:

    Thread t1 = new Thread(()->
    {
        synchronized (array_fib){
            for(int i = 0; i < array_fib.length; i++)
                if(i % 2 == 0) {
                    System.out.println("Thread 1:" + array_fib[i]);
                    try {
                        array_fib.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                else
                    array_fib.notify();
        }
    });
    Thread t2 = new Thread(()->
    {
        synchronized (array_fib){
            for(int i = 0; i < array_fib.length; i++)
                if(i % 2 != 0) {
                    System.out.println("Thread 2:" + array_fib[i]);
                    try {
                        array_fib.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                else
                    array_fib.notify();
        }
    });
    

    我们可以通过提取将分配给线程的工作的方法来消除代码冗余。例如:

    private static void printFib(String threadName, int[] array_fib, Predicate<Integer> predicate) {
        for (int i = 0; i < array_fib.length; i++)
            if (predicate.test(i)) {
                System.out.println(threadName + " : " + array_fib[i]);
                try { 
                     array_fib.wait();
                } catch (InterruptedException e) {
                    // do something about it
                }
            } else
                array_fib.notify();
    }
    

    及主要代码:

    public static void main(String[] args) throws Exception{
        int [] array_fib = new int[10];
        Fibonacci f = new Fibonacci();
        f.getFibonacci(array_fib);
        Thread t1 = new Thread(()-> {
            synchronized (array_fib){
                printFib("Thread 1:", array_fib, i1 -> i1 % 2 == 0);
            }
        });
        Thread t2 = new Thread(()-> {
            synchronized (array_fib){
                printFib("Thread 2:", array_fib, i1 -> i1 % 2 != 0);
            }
        });
        t1.start();
        t2.start();
        t1.join();
        t2.join();
    }
    

    【讨论】:

      【解决方案2】:

      作为替代方案,您可以使用公平的Semaphore 在线程之间交替,并使用AtomicReference 来保持共享状态。这是一个例子:

      import java.util.concurrent.Semaphore;
      import java.util.concurrent.atomic.AtomicReference;
      
      public class FibonacciConcurrent {
        public static void main(String[] args) throws InterruptedException {
          // needs to be fair to alternate between threads
          Semaphore semaphore = new Semaphore(1, true);
          // set previous to 1 so that 2nd fibonacci number is correctly calculated to be 0+1=1
          Status initialStatus = new Status(1, 0, 1);
          AtomicReference<Status> statusRef = new AtomicReference<>(initialStatus);
          Fibonacci fibonacci = new Fibonacci(20, semaphore, statusRef);
          Thread thread1 = new Thread(fibonacci);
          Thread thread2 = new Thread(fibonacci);
          thread1.start();
          thread2.start();
          thread1.join();
          thread2.join();
        }
      
        private static final class Status {
          private final long previous;
          private final long current;
          private final int currentIndex;
      
          private Status(long previous, long current, int currentIndex) {
            this.previous = previous;
            this.current = current;
            this.currentIndex = currentIndex;
          }
        }
      
        private static final class Fibonacci implements Runnable {
      
          private final int target;
          private final Semaphore semaphore;
          private final AtomicReference<Status> statusRef;
      
          private Fibonacci(int target, Semaphore semaphore, AtomicReference<Status> statusRef) {
            this.target = target;
            this.semaphore = semaphore;
            this.statusRef = statusRef;
          }
      
          @Override
          public void run() {
            try {
              process();
            } catch (InterruptedException e) {
              Thread.currentThread().interrupt();
              throw new RuntimeException("Interrupted", e);
            }
          }
      
          private void process() throws InterruptedException {
            while (!Thread.currentThread().isInterrupted()) {
              try {
                semaphore.acquire();
                Status status = statusRef.get();
                String threadName = Thread.currentThread().getName();
                if (status.currentIndex > target) return;
                System.out.println(
                    threadName + ": fibonacci number #" + status.currentIndex + " - " + status.current);
                long next = status.previous + status.current;
                Status newStatus = new Status(status.current, next, status.currentIndex + 1);
                statusRef.set(newStatus);
              } finally {
                semaphore.release();
              }
            }
          }
        }
      }
      

      将打印:

      Thread-0: fibonacci number #1 - 0
      Thread-1: fibonacci number #2 - 1
      Thread-0: fibonacci number #3 - 1
      Thread-1: fibonacci number #4 - 2
      Thread-0: fibonacci number #5 - 3
      

      请注意,此解决方案不仅在线程上打印 - 它也在线程上进行实际计算 - 例如当轮到线程A时,它使用线程B计算的先前状态来计算下一个斐波那契数。

      【讨论】:

        【解决方案3】:

        除了已经说过和已经回答的所有内容之外,我只想添加一种替代方法来实现斐波那契数列,无需数组和预先标注:

        public class Fibonacci {
        
            private int index = -1;
        
            private int previous = 0;
            private int last = 1;
        
            synchronized public int getNext() {
        
              index++;
        
              if( index == 0 ) return previous;
              if( index == 1 ) return last;
        
              int next = last + previous;
              if( next < 0 ) throw new ArithmeticException( "integer overflow" );
        
              previous = last;
              last = next;
        
              return next;
            }
        
        }
        

        仅受数字数据类型溢出的限制,在本例中为整数。

        【讨论】:

          【解决方案4】:

          您的代码中的以下行是causing t1 to finish before t2 can start

          t1.join();
          

          除此之外,还需要同步方法printFibonacci

          你可以这样做:

          class Fibonacci {
              synchronized void printFibonacci() throws InterruptedException {
                  int fibArray[] = new int[10];
                  int a = 0;
                  int b = 1;
                  fibArray[0] = a;
                  fibArray[1] = b;
                  int c;
                  for (int i = 2; i < 10; i++) {
                      c = a + b;
                      fibArray[i] = c;
                      a = b;
                      b = c;
                  }
                  for (int i = 0; i < 10; i++) {
                      String currentThreadName = Thread.currentThread().getName();
                      if (currentThreadName.equals("1")) {
                          if (i % 2 == 0) {
                              System.out.println("Thread " + Thread.currentThread().getName() + " " + fibArray[i]);
                              notify();
                          } else {
                              wait();
                          }
                      } else if (currentThreadName.equals("0")) {
                          if (i % 2 == 1) {
                              System.out.println("Thread " + Thread.currentThread().getName() + " " + fibArray[i]);
                              notify();
                          } else {
                              wait();
                          }
                      }
                  }
              }
          }
          
          public class Main {
              public static void main(String[] args) {
          
                  Fibonacci f = new Fibonacci();
                  Thread t1 = new Thread(() -> {
                      try {
                          f.printFibonacci();
                      } catch (InterruptedException e) {
                          e.printStackTrace();
                      }
                  });
                  Thread t2 = new Thread(() -> {
                      try {
                          f.printFibonacci();
                      } catch (InterruptedException e) {
                          e.printStackTrace();
                      }
                  });
                  t1.setName("0");
                  t2.setName("1");
                  t1.start();
                  t2.start();
              }
          }
          

          输出:

          Thread 1 0
          Thread 0 1
          Thread 1 1
          Thread 0 2
          Thread 1 3
          Thread 0 5
          Thread 1 8
          Thread 0 13
          Thread 1 21
          Thread 0 34
          

          【讨论】:

            猜你喜欢
            • 2016-02-17
            • 1970-01-01
            • 2020-04-02
            • 1970-01-01
            • 2018-04-04
            • 1970-01-01
            • 1970-01-01
            • 2013-03-27
            • 1970-01-01
            相关资源
            最近更新 更多