Q:

¿Cómo calcular el factorial de un número en Java usando hilos?

Tengo que hacer el factorial de un numero, haciendo en un hilo la primera parte y en otro la segunda, el problema es que funcionan por separado pero al ponerlos juntos no me dan el resultado, me dan otros.
import java.util.Scanner;
public class Threads extends Thread {
    private static  int numero;
    private static long resultado;
    public static int i;

    public Threads(int i,int numero, long resultado) {
        this.numero=numero;
        this.resultado=resultado;
    }

    public synchronized void factorial() {
        for(i=Threads.i; i<=numero; i= i+1 ) {
            System.out.println(i   +"x" +resultado);
            resultado= resultado*i;
        }
        System.out.println(resultado);
    }

    public void run() {
        factorial();    
    }

    public static void main (String[]args ) {
        Scanner scan = new Scanner(System.in);
        System.out.println("Factorial del numero: ");
        numero = scan.nextInt();
        Threads hilo1 = new Threads(i=1,((numero/2)), resultado=1);
        Threads hilo2 = new Threads(i=(numero/2)+2, numero, resultado = 
        ((numero/2)+1));
        hilo1.start();  
    }
}

A:

tl;dr
La siguiente respuesta intenta explicar el uso de hilos y concurrencia en Java de la manera más simple posible. Se explica un hack para realizar el proceso sin concurrencia real y luego se explica la forma de hacerlo con concurrencia.
PROBLEMA
Se desea calcular el factorial de un número entero usando hilos. El resultado final debe ser mostrado en pantalla.
SOLUCIÓN
Para este ejemplo asumiré que el OP ha hecho los deberes y sabe (tiene conocimiento de) lo siguiente:

Thread
Runnable

En todo caso, una lectura recomendada es: Oracle Java Tutorial - Concurrency, donde se puede aprender lo básico para trabajar con hilos (threads).
Lo primero que vamos a hacer es definir una función que calcule el factorial, pero no será una función tradicional.
¿Recursividad? "Primero hay que usar recursividad para usar recursividad".
Una función recursiva para calcular el factorial de un número puede verse así:
long factorial(long n) {
    if(n < 2) {
        return 1;
    } else {
        return n*factorial(n-1);
    }
}

Esta función desbordaría la pila de memoria rápidamente, además el máximo número factorial (seguro) que podríamos representar usando un tipo long sería 20!. No muy poderosa nuestra función.
Sin recursividad. No llenemos la pila sin necesidad
Una función no recursiva simplemente usaría un iterador, así no llenamos la pila, sino que iteramos desde 2 hasta n y vamos multiplicando sus términos.
long factorial(long n) {
    long result = 1;
    if(n > 1) {
        for(int i = 2; i <= n; i++) {
            result = result * i;
        }
    }
    return result;
}

El tamaño importa.
Ahora que ya resolvimos el problema de la pila, debemos resolver el problema de la máxima representación numérica posible. Para esto debemos introducir la clase BigInteger de Java.
Si leemos la documentación vemos que dicha clase soporta la asombrosa cifra positiva de (2^Integer.MAX_VALUE) - 1. Si tomamos en cuenta que:
Integer.MAX_VALUE => 2.147.483.647

Entonces, el valor numérico que podemos representar usando la clase BigInteger será tan grande como la capacidad en RAM de nuestro equipo. Luego viene el tema de poder mostrar dicho número en pantalla, teniendo en cuenta que el tamaño máximo para un tipo string es de (2^31) -1. Pero todo esto es harina de otro costal. Para calcular factoriales pequeños (pero más grandes que 20!), nos basta con usar esta clase.
¿Thread, Runnable?
Aquí es donde se necesita algo de conocimiento de lo que significa trabajar con hilos. Y no me refiero a costuras precisamente.
De forma muy amplia, la idea de hilo (thread en inglés) se refiere a la posibilidad de usar la capacidad que tiene un ordenador (computador) de realizar múltiples tareas a la vez, es decir, de forma concurrente.
No confundir proceso con hilo. Si bien podrían asemejarse, porque ambos generan un entorno de ejecución, un hilo requiere menos recursos que un proceso, además de algunas otras diferencias.
Los hilos por su parte existen dentro de un proceso, y podemos tener tantos hilos ejecutándose a la vez, como nuestro equipo soporte.
Para implementar el uso de hilos, vamos a valernos del siguiente patrón:

Crear, administrar y gestionar directamente el hilo, mediante el uso de una instancia de la clase Thread.

Una vez que tenemos nuestra instancia de la clase Thread debemos definir el código que deseamos ejecutar en nuestro hilo. Esto lo conseguimos de las siguientes dos formas:

Usando un Objeto Runnable y pasando dicho objeto como argumento al constructor de la clase Thread.
Creando una clase que extienda de Thread, la cual a su vez implementa Runnable.

Si bien, ambos estilos son válidos, la diferencia está en que usando un Objeto Runnable tendremos  un mayor control sobre lo que deseamos ejecutar en nuestro hilo, y no necesitamos que nuestra aplicación extienda de la clase Thread. Aunque para gustos, los colores.
Veremos la forma de hacerlo usando estos dos tipos de aproximaciones.
Sin embargo, en esta primera parte haremos trampa. Si bien la idea de calcular el valor de un factorial, usando hilos, es o puede ser muy interesante desde el punto de vista de entender los procesos relativos al uso de hilos, existe algo llamado concurrencia. Y es que esta primera aproximación, la haré separando los hilos y sus resultados, para combinarlos al final. Lo cual no es un proceso concurrente real. Pero servirá para introducirnos al mundo de la concurrencia.
Hack: sin concurrencia
Runnable
Vamos a crear un Objeto Runnable y lo llamaremos Factorial el cual tendrá las siguientes propiedades y métodos privados:

start: valor inicial desde que se realizará la multiplicación para calcular nuestro número factorial.
end: valor final hasta el cual se multiplicarán los elementos de nuestro factorial.
result: valor calculado por nuestra función factorial.
factorial(start, end): método que realiza el cálculo del factorial.

Además tendremos los siguiente métodos públicos:

Factorial(start, end): constructor de la clase Factorial.
run(): método que se ejecutará cuando se llame al método start() del hilo.
getResult(): método que nos devolverá el valor calculado del factorial.

Con esto ya podemos escribir nuestro Objeto Runnable:
class Factorial implements Runnable {
  private BigInteger start = BigInteger.ONE;
  private BigInteger end = BigInteger.ONE;
  private BigInteger result = BigInteger.ONE;

  private BigInteger factorial(BigInteger start, BigInteger end) {
    BigInteger res = BigInteger.ONE;
    if(end.compareTo(BigInteger.ONE) > 0) {
      int value = end.intValue();
      for(int i = start.intValue(); i <= value; i++) {
        BigInteger index = new BigInteger(String.valueOf(i));
        res = res.multiply(index);
      }
    }
    return res;
  }

  public Factorial(BigInteger start, BigInteger end) {
    this.start = start;
    this.end = end;
  }

  public void run() {
    this.result = factorial(start, end);
  }

  public BigInteger getResult() {
    return this.result;
  }
}

Ahora podemos escribir una aplicación que calcule el factorial de un número por partes. Sin embargo, esto no es un proceso concurrente, y lo veremos más adelante.
Para usar este Objeto y sus propiedades podemos hacerlo de la siguiente manera:

Se captura el valor introducido por el usuario.
Se calcula la mitad de dicho valor, para usar 2 hilos: Uno calculará la mitad inferior del valor y el otro la mitad superior.
Se obtiene el resultado de cada Objeto Runnable una vez que el hilo ha finalizado de ejecutarse.
Se multiplican ambos valores para obtener el resultado final.

El código podría verse así:

public class runnableFactorial{
  public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    System.out.println("Introduzca un número entero:");
    BigInteger number = sc.nextBigInteger();
    BigInteger half = number.divide(BigInteger.valueOf(2));
    Factorial f1 = new Factorial(BigInteger.ONE, half);
    Factorial f2 = new Factorial(half.add(BigInteger.ONE), number);
    Thread t1 = new Thread(f1);
    Thread t2 = new Thread(f2);
    t1.start();
    t2.start();
    try {
      t1.join();
    } catch(InterruptedException e1) {
      e1.printStackTrace();
    }
    try {
      t2.join();
    } catch(InterruptedException e2) {
      e2.printStackTrace();
    }
    BigInteger fact = f1.getResult().multiply(f2.getResult());
    System.out.println("El factorial es:");
    System.out.println(fact);
    sc.close();
  }
}

Notemos que al constructor de cada hilo, le hemos pasado como argumento el Objeto Runnable, El mismo es instanciado con los valores necesarios para que realice los cálculos que necesitamos.
Al final, cuando el hilo ha terminado su ejecución, obtenemos el valor almacenado en cada Objeto Runnable y los multiplicamos, para obtener así el valor de nuestro factorial.
Thread
Para hacer el mismo proceso anterior, sin usar un Objeto Runnable, debemos crear una Clase que extienda de la clase Thread y que implemente un método run(). 
Los métodos y propiedades públicas y privadas son iguales, sin embargo nuestra Clase extiende de la Clase Thread, mientras que el Objeto Runnable simplemente implementa la interfaz Runnable.
class Factorial extends Thread {
  private BigInteger start;
  private BigInteger end;
  private BigInteger result;

  private BigInteger factorial(BigInteger start, BigInteger end) {
    BigInteger res = BigInteger.ONE;
    if(end.compareTo(BigInteger.ONE) > 0) {
      int value = end.intValue();
      for(int i = start.intValue(); i <= value; i++) {
        BigInteger index = new BigInteger(String.valueOf(i));
        res = res.multiply(index);
      }
    }
    return res;
  }

  public Factorial(BigInteger start, BigInteger end) {
    this.start = start;
    this.end = end;
  }

  public void run() {
    this.result = factorial(start, end);
  }

  public BigInteger getResult() {
    return this.result;
  }
}

Para implementar nuestro programa usando esta Clase, podríamos escribir algo parecido a lo siguiente:
public class threadFactorial{
  public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    System.out.println("Introduzca un número entero:");
    BigInteger number = sc.nextBigInteger();
    BigInteger half = number.divide(BigInteger.valueOf(2));
    Factorial f1 = new Factorial(BigInteger.ONE, half);
    Factorial f2 = new Factorial(half.add(BigInteger.ONE), number);
    f1.start();
    f2.start();
    try {
      f1.join();
    } catch(InterruptedException e1) {
      e1.printStackTrace();
    }
    try {
      f2.join();
    } catch(InterruptedException e2) {
      e2.printStackTrace();
    }
    BigInteger fact = f1.getResult().multiply(f2.getResult());
    System.out.println("El factorial es:");
    System.out.println(fact);
    sc.close();
  }
}

Nuevamente vemos que para obtener el resultado, hemos multiplicado los valores almacenados en cada Objeto (f1 y f2). Nuevamente, si bien hemos usado hilos, el proceso no ha sido concurrente.
Concurrencia
La idea tras un proceso concurrente es que podamos acceder a una variable en memoria, desde cada hilo que la necesite, y que cada hilo no sólo pueda leer un valor actualizado de dicha variable, sino que pueda establecer un nuevo valor, todo esto sin importar cuántos hilos se estén ejecutando y logrando que cada hilo acceda al último valor que se guardó, es decir, el más actualizado.
Esto nos plantea un reto importante: la sincronización, y aunque sería muy interesante poder explicar todos los aspectos de este reto, eso se escapa al propósito general de la respuesta, que ya es extensa de por sí.
En pocas palabras, la idea es evitar que los hilos solapen sus procesos, lo cual podría producir datos incorrectos.
En este caso en particular, nuestra variable será multiplicada por un valor y este será su nuevo valor asignado. Este proceso implica 3 pasos: leer el valor actual, calcular el nuevo valor, escribir el valor calculado. Por lo tanto, y dado que esta operación no es atómica, tenemos riesgo de solapamiento. 
Si nuestra operación fuese atómica, podríamos hacer uso de una variable tipo volatile, pero en este caso, usaremos un método de tipo synchronized.
Si se desea una mejor explicación del proceso de sincronización, se puede consultar la sección Synchronization del tutorial de Java.
Lo primero que haremos es crear una clase llamada Factorial la cual tendrá una propiedad para almacenar el valor de nuestro factorial, un método para obtener dicho valor y un método sincronizado para bloquear su ejecución desde que inicia hasta que termina. Esto nos permite evitar el solapamiento cuando el método es llamado desde un hilo, y se traduce en bloquear el acceso o la ejecución a dicho método desde otro hilo, mientras haya un hilo que posea el acceso al método.
Clase Factorial
import java.math.BigInteger;

public class Factorial {
  private BigInteger factorial = BigInteger.One;

  public BigInteger get() {
    return this.factorial;
  }

  public synchronized update(BigInteger value) {
    this.factorial = this.factorial.multiply(value);
  }
}

Observamos que el método update ha sido declarado como synchronized, por lo cual, cuando un hilo llame a este método, no podrá ser llamado por otro hilo hasta que su ejecución finalice.
Ahora, podemos crear nuestra clase Runnable, la cual tendrá un aspecto parecido a lo que ya habíamos realizado, pero con un ligero cambio. Si nos percatamos, la operación de multiplicación ahora está en el método update de la clase Factorial, por lo tanto, por cada iteración de nuestro bucle for sólo debemos llamar a dicho método, pasando como argumento el valor apropiado.
Otra diferencia, es que a nuestro constructor, ahora le pasaremos una referencia al Objeto Factorial que instanciaremos una sola vez.
Clase MyRunnable
import java.math.BigInteger;

public class MyRunnable implements Runnable {
  private BigInteger start;
  private BigInteger end;

  protected Factorial factorial = null;

  public MyRunnable(BigInteger start, BigInteger end, Factorial factorial) {
    this.start = start;
    this.end = end;
    this.factorial = factorial;
  }

  public void run() {
    if(end.compareTo(BigInteger.ONE) > 0) {
      int value = end.intValue();
      for(int i = start.intValue(); i <= value; i++) {
        BigInteger index = new BigInteger(String.valueOf(i));
        factorial.update(index);
      }
    }
  }
}

Notemos que en el método run() hemos escrito la lógica del cálculo del factorial, y dentro del bucle llamamos al método sincronizado update() de nuestra clase Factorial.
Una implementación completa de este programa usando este Objeto Runnable podría verse como la siguiente:
import java.util.Scanner;
import java.math.BigInteger;

public class ProgramFactorial {
  public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    System.out.println("Introduzca un número entero:");
    BigInteger number = sc.nextBigInteger();
    BigInteger half = number.divide(BigInteger.valueOf(2));

    Factorial factorial = new Factorial();
    MyRunnable r1 = new MyRunnable(BigInteger.ONE, half, factorial);
    MyRunnable r2 = new MyRunnable(half.add(BigInteger.ONE), number, factorial);

    Thread t1 = new Thread(r1);
    Thread t2 = new Thread(r2);

    t1.start();
    t2.start();

    try {
      t1.join();
    } catch(InterruptedException e1) {
      e1.printStackTrace();
    }
    try {
      t2.join();
    } catch(InterruptedException e2) {
      e2.printStackTrace();
    }
    System.out.println("El factorial es:");
    System.out.println(factorial.get());
    sc.close();
  }
}

Como podemos observar, se crea una única instancia de Factorial y la misma se pasa como argumento al constructor de cada Objeto Runnable, por lo tanto, ambos hilos actualizan la misma variable de forma concurrente, y dado que nuestro método de actualización es sincronizado, el resultado será el esperado, sin inconsistencia.

Para comparar resultados de esta implementación se puede visitar la siguiente calculadora en línea para factoriales: Online Math Tools - Factorial Calculator
Lectura recomendada: Java Concurrency and Multithreading Tutorial

