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-02-04 19:41:07

问题


I want fibonacci series to be printed by threads and the 1st number of the series should be printed by 1st thread then 2nd number by 2nd thread then 3rd by 1st thread and 4th by 2nd and so on.

I tried this code by using arrays like printing the array elements using thread but I am not able to switch between the threads.

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();
    }
}

回答1:


The following line in your code is causing t1 to finish before t2 can start.

t1.join();

Apart from this, you need to synchronize on the method, printFibonacci.

You can do it as follows:

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();
    }
}

Output:

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



回答2:


As "@Live and Let Live" pointed out, correctness-wise the main issues with your code is the missing synchronized clause and calling join of the first thread before starting the second thread.

IMO you could clean the code a bit by first separating a bite the concerns, namely, the class Fibonacci would only responsible for calculation the Fibonacci of a given array:

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;
        }
    }
}

In this way, you keep your Fibonacci class concise without any thread-related code. Moreover, the getFibonacci is now more abstract; you can calculate the fib of more than just 10 elements like you had before.

Then on the class 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();
        }
    }

First, you calculate the Fibonaccis using the main thread, there is no point in having all the threads calculate the same thing. Afterward, you specified that Thread 1 and Thread 2 will print the even and odd positions, respectively.

Unless this is just an exercise to play around with threads and synchronization there is not much sense in using threads to do this kind of work. In your code, the part worth parallelizing is the calculation of the Fibonacci numbers themselves, not the printing part.

The code previously shown will not print the Fibonacci numbers in order, for that you need to ensure that the threads wait for one another after iterating through each element of the array. Hence, you need to adapt the code that will be executed by the threads, namely:

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();
    }
});

We can remove the code redundancy by extracting a method with the work that will be assigned to the Threads. For instance:

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();
}

and the main code:

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();
}



回答3:


Apart from all being said and already answered, I would just like to add one alternative approach to Fibonacci sequence implemetation, without arrays and in-advance dimensioning:

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;
    }

}

Limited only by overflow of numeric data type, in this case integer.




回答4:


As an alternative, you can use a fair Semaphore to alternate between threads, and an AtomicReference to keep the shared status. Here's an example:

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();
        }
      }
    }
  }
}

Will print:

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

Note that this solution does not only print on the threads - it does the actual calculation on the threads as well - e.g. when it's Thread A's turn, it uses the previous status that was calculated by Thread B to calculate the next fibonacci number.



来源:https://stackoverflow.com/questions/65464317/i-want-to-print-the-fibonacci-series-using-two-threads-like-1st-number-should-b

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!