繁体   English   中英

我想使用两个线程打印斐波那契数列。 比如第一个数字应该由第一个线程打印,然后第二个数字由第二个线程打印,依此类推

[英]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

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

我通过使用 arrays 尝试了此代码,就像使用线程打印数组元素一样,但我无法在线程之间切换。

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

代码中的以下行导致t1t2可以开始之前完成

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

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

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

IMO您可以通过首先分离一点关注点来清理代码,即 class 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 class 简洁,无需任何与线程相关的代码。 此外, getFibonacci现在更加抽象; 您可以像以前一样计算不止 10 个元素的fib

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

首先,您使用线程计算斐波那契,让所有线程计算相同的东西是没有意义的。 之后,您指定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();
}

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

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

}

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

作为替代方案,您可以使用公平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 计算的先前状态来计算下一个斐波那契数。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM