我想用两个线程打印斐波那契级数像第一个数字应该用第一条线打印,然后第二个数字用第二条线打印,依此类推

rqcrx0a6  于 2021-06-29  发布在  Java
关注(0)|答案(4)|浏览(219)

我要斐波那契数列用线打印,数列的第一个数应该用第一个线打印,第二个数用第二个线打印,第三个数用第一个线打印,第四个数用第二个线打印,依此类推。
我使用数组尝试了这段代码,比如使用线程打印数组元素,但是我无法在线程之间切换。

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

brgchamk1#

作为一种选择,你可以使用一个公平的 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计算的先前状态来计算下一个斐波那契数。

eiee3dmh

eiee3dmh2#

代码中的以下行导致 t1 在…之前完成 t2 我们可以开始了。

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
kqqjbcuj

kqqjbcuj3#

除了以上所说的和已经回答的,我只想为斐波那契序列的实现添加一种替代方法,不使用数组和预先标注尺寸:

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

}

仅受数值数据类型(在本例中为整数)溢出的限制。

nfeuvbwi

nfeuvbwi4#

正如“@live and let live”所指出的,代码的主要问题是缺少 synchronized 条款与调用 join 在开始第二个线程之前。
在我看来,您可以通过首先分离关注点(即类)来稍微清理代码 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 现在更抽象了;你可以计算 fib 而不是像你以前那样的10种元素。
然后上课 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();
        }
    }

首先,使用主线程计算fibonaccis,让所有线程计算相同的东西是没有意义的。后来,你指定 Thread 1 以及 Thread 2 将分别打印偶数和奇数位置。
除非这只是一个使用线程和同步的练习,否则使用线程来完成这类工作没有多大意义。在您的代码中,值得并行化的部分是斐波那契数本身的计算,而不是打印部分。
前面显示的代码不会按顺序打印fibonacci数,因为您需要确保线程在遍历数组的每个元素之后彼此等待。因此,您需要调整将由线程执行的代码,即:

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

相关问题