Como criar Multithreads em java ?

Estou treinando em um exercício que eu mesmo elaborei, porém estou com uma certa dificuldade de aplica-lo em código. Estou recebendo o erro Thread.start(Unknown Source);

O que esta faltando em meu código?
Eu implementei corretamente o conceito básico?

Estou usando Threads para simular um tanque de água associado a duas
torneiras: uma usada para encher o tanque e outra usada para esvaziar o tanque.

Regras:

a) A capacidade total do tanque é de 2000 litros e cada “bolinha” representa 10 litros.
b) A torneira que enche o tanque tem uma vazão de 10 litros a cada 150 ms
(milissegundos).
c) A torneira que esvazia o tanque tem uma vazão de 30 litros a cada 150 ms (milissegundos).
d) O controlador do tanque é responsável por abrir e fechar as torneiras.
e) Quando o tanque atinge seu volume máximo, a torneira de enchimento é fechada e a
torneira de esvaziamento é aberta.
f) Quando o tanque estiver abaixo de 50% do seu volume a torneira de enchimento deverá ser aberta.
g) Quando o volume de água ficar abaixo da torneira de esvaziamento, essa torneira
deverá ser fechada

import java.util.Scanner;

public class Main {
	private static Scanner sc = new Scanner(System.in);
	
	public static void main(String[] args) {
		int inputQuantity;
		
		System.out.println("Do you want to run how many times?");
		inputQuantity = sc.nextInt();
		
		Controller c = new Controller(inputQuantity);
		c.start();
		
	}

}

public class Controller extends Thread {
	private int inputQuantity = 0;
	private Tank tank = new Tank();
	private Faucet faucetA = new Faucet(10);
	private Faucet faucetB = new Faucet(30);
	
	public Controller (int inputQuantity) {
		this.inputQuantity = inputQuantity;
	}
	
@SuppressWarnings("deprecation")
	@Override
public void run() {
	for(int i = 0; i < this.inputQuantity; i++) {
		System.out.println("FILLING THE TANK. TXSIIIIIIIII... \n");
		
		if (this.tank.getPercentageWater() < 50) {
			System.out.println("TANK AT 50% CAPACITY!. CLOSING EMPTYING TAP.. \n");
			this.faucetB.stop();
			
			System.out.println("FILLING TAP OPEN!");
    		this.faucetA.start();
    		this.tank.addWater(this.faucetA.getLiterLeakage());	
		} else if (this.tank.getPercentageWater() == 100) {
			System.out.println("TANK AT 50% CAPACITY!. CLOSING FILLING TAP OPEN!.. \n");
			this.faucetA.stop();
			
			System.out.println("EMPTYING TAP OPEN!");
			this.faucetB.start();
			this.tank.removeWater(this.faucetB.getLiterLeakage());	
		}
	}
	
}
}

public class Faucet extends Thread {
	private int literLeakage;
	private long timeMax = 150; // ms
	
	public Faucet(int literLeakage) {
		this.setLiterLeakage(literLeakage);
	}
	
@Override
public void run() {
	try {
			Thread.sleep(this.timeMax);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
}

	public int getLiterLeakage() {
		return literLeakage;
	}

	public void setLiterLeakage(int literLeakage) {
		this.literLeakage = literLeakage;
	}
}
import java.math.BigDecimal;

public class Tank {
	int maximumVolume = 2000; // litros
	int volumeOfWater = 0; // litros
	
	private int getVolumeOfWater() {
		return (this.volumeOfWater <= 0) ? 0 : this.volumeOfWater;
	}
	
	public void addWater(int litersOfWater) {
		if (this.getVolumeOfWater() < this.maximumVolume)
			this.volumeOfWater += litersOfWater;
			System.out.println("FILLING... GUP GUP GUP");
	}
	
	public void removeWater(int litersOfWater) {
		if (this.getVolumeOfWater() != 0)
			this.volumeOfWater -= litersOfWater;
			System.out.println("EMPTYING.. TSXXXXXXIIIIIIIIIII");
	}
	
	public double getPercentageWater() {
		BigDecimal value = new BigDecimal(this.maximumVolume);
		BigDecimal rate  = new BigDecimal(this.getVolumeOfWater());
		BigDecimal percentage = rate.divide(value).multiply(new BigDecimal("100"));
		
		return percentage.doubleValue();
	}	
	
}

Posta o StackTrace

ISSO?

   Do you want to run how many times?
    5
    FILLING THE TANK. TXSIIIIIIIII... 

    TANK AT 50% CAPACITY!. CLOSING EMPTYING TAP.. 

    FILLING TAP OPEN!
    FILLING... GUP GUP GUP
    FILLING THE TANK. TXSIIIIIIIII... 

    TANK AT 50% CAPACITY!. CLOSING EMPTYING TAP.. 

    FILLING TAP OPEN!
    Exception in thread "Thread-0" java.lang.IllegalThreadStateException
    	at java.lang.Thread.start(Unknown Source)
    	at Controller.run(Controller.java:22)

Não. Stacktrace é o “erro”, ou seja, o output no console quando seu programa “quebra”.

Exception in thread "Thread-0" java.lang.IllegalThreadStateException
	at java.lang.Thread.start(Unknown Source)
	at Controller.run(Controller.java:22)

Qual é o conteúdo da linha 22 do arquivo Controller.java?
Não dá pra identificar no código postado.

Isso dá quando você ta chamando start() duas vezes pra mesma thread.

@Kronal, como eu faço para deixar a minha lógica correta? Realmente fiquei meio perdido agora.

@staroski foi o que o @Kronal disse abaixo, mas agora eu fiquei meio perdido e não sei como implementar a lógica corretamente.

Acho que começa por entender melhor o problema, e a sequencia de como as ações se dão e o que causa elas, etc.

Eu faria definindo uma maquina de estados, dai definiria que só daria pra fazer transição pra abrir a torneira X a partir de estados onde ela só pode estar fechada.

Dai definiria isso no papel mesmo e depois implementaria a maquina de estados usando um enum com cada possível estado e um switch/case dentro de um loop pra ir alternando, ou coisa do tipo, tem gente que gosta de complicar e faz uma hierarquia de classes, com classes filha pra cada estado :astonished: rs