我希望斐波那契数列由线程打印,该系列的第一个数字应由第一个线程打印,然后由第二个线程打印第二个数字,然后由第一个线程打印第三个,依此类推。
我通过使用数组尝试了此代码,例如使用线程打印数组元素,但我无法在线程之间切换。
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();
}
}
答案 0 :(得分:3)
代码中的以下行是 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
答案 1 :(得分:1)
正如“@Live and Let Live”所指出的,在正确性方面,您的代码的主要问题是缺少 synchronized
子句以及在启动第二个线程之前调用第一个线程的 join
。< /p>
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();
}
}
首先,您使用主线程计算斐波那契数列,让所有线程计算相同的东西是没有意义的。之后,您指定 Thread 1
和 Thread 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 :(得分:0)
除了已经说过和已经回答的所有内容之外,我只想为 Fibonacci 序列实现添加一种替代方法,无需数组和预先标注:
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;
}
}
仅受数字数据类型溢出的限制,在本例中为整数。
答案 3 :(得分:0)
作为替代方案,您可以使用公平的 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 计算的前一个状态来计算下一个斐波那契数。