Let's think about the fundamental problem here. You want your code to perform faster on the same hardware, an important software process called optimization.
During optimization, you'll need to profile your application to determine what is the slowest component and improve upon that. In your case, I can guess with a good degree of certainty in that the slowest component of your program here is the function call. Plotting the nth Fibonacci term against the number of function calls we get:

as you can see, the growth is exponential. Note: there are mathematical ways to figure this out, notably as explained on this page. Exponential growth in time complexity is always something to avoid if your intentions are to make a fast executing function (granted, there are functions that have to be exponential but this is not one of them). Looking at cycle(50)
, taking over 4 * 10^10 function calls, you said it finished in nearly a minute which equates to about 666.6 million function calls per second (or 1 call per 1.5 ns), hardly seems fair to call java slow based on that. The bottom line is, it doesn't matter how good or fast the compiler's optimization techniques get, it won't be able to fix your time complexity, it can only make each operation slightly faster (read tail-call optimization if you want to know more).
The primary issue you are having here is that you are recomputing the same Fibonacci numbers many many times, think of how many times you are recomputing cycle(2)
. That's where the exponential complexity is coming from, recomputing the same Fibonacci numbers many many times, which is useless.
The easiest way to solve the issue is via iteration but you've expressed your disinterest in iterator.
The next easy way is to use a look up table (LUT) storing precomputed Fibonacci numbers in an array for fast access. The problem with this approach can be easily shown below:

The graph above shows the effects of the LUT of n up to 10. whilst we have reduced the power of the exponent, we are still dealing with exponentials which doesn't solve the problem entirely (suppose you need to do cycle(100)
what then?).
The solution is to use memorization as mentioned in user 1.618's comment. What this means is to save the result of each Fibonacci term as you are calculating it, generating the LUT as you go, never recomputing any result twice.
The following graph demonstrates the effects of this:

at cycle(50)
, you'll need 97 method calls, which at a speed of 1.5 ns/call will finish in 145.5 ns, faster than you can blink (it probably won't do it that fast due to additional time looking at the LUT as well as well as not warming up as much).
Implementing this in java, we get:
private static long[] fib_numbers;
public static long cycle(int x){
if(fib_numbers == null || fib_numbers.length <= x){
fib_numbers = new long[x + 1];
}
return cycle_rec(x);
}
private static long cycle_rec(int x) {
if(x <= 1){
return x;
}else if(fib_numbers[x] != 0){
// previously computed result exists, return directly
return fib_numbers[x];
}else{
// compute and store cycle(x)
fib_numbers[x] = cycle_rec(x-1)+cycle_rec(x-2);
return fib_numbers[x];
}
}
the array fib_numbers
holds the LUT we dynamically generate per method call. We expose a public method cycle()
to setup the array for use before internally calling cycle_rec()
(our recursive function).