I have this program which is a window with 20 bouncing balls (threads) which have randomly generated size, speed, direction and location. They also have a randomly generated maximum number of bounces against the walls they can take. When that number is exceeded the Thread stops its work. 
My question would be how could I incorporate a ThreadPool into the program so that when one Thread stops its work a new one is started instead of it?
public class BouncingBalls extends JPanel{
    private ArrayList<Ball> balls = new ArrayList<Ball>();
    private static final long serialVersionUID = 1L;
    private static final int box_width = 1000;
    private static final int box_height = 800;
    public BouncingBalls() {
        this.setPreferredSize(new Dimension(box_width, box_height));
        createBalls();
        gameStart();
    }
   public void createBalls(){
        for(int i=0;i<20;i++){
            Ball ball = new Ball(this);
            balls.add(ball);
        }
    }
   public void gameStart() {
       Thread gameThread = new Thread() {
           public void run() {
               for(Ball b : balls){
                   b.start();
               }
            }
      };
      gameThread.start();
   }
   @Override
    public void paintComponent(Graphics g)  {
       super.paintComponent(g);
       Graphics2D g2d = (Graphics2D) g;
       for(Ball b : balls){
            b.draw(g2d);
       }
   }
   public static void main(String[] args) {
      javax.swing.SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            JFrame frame = new JFrame("Bouncing Balls");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setContentPane(new BouncingBalls());
            frame.pack();
            frame.setVisible(true);
         }
      });
   }
}   
public class Ball extends Thread{
    private Ellipse2D.Double thisBall;
    private int posX;
    private int posY;
    private int radius;
    private int maxBounces;
    private int bounces = 0;
    private int deltaX, deltaY;
    private BouncingBalls mainWindow;
    public Ball(BouncingBalls mainWindow){
        this.posX = 0 + (int)(Math.random() * ((975 - 0) + 1));
        this.posY = 0 + (int)(Math.random() * ((775 - 0) + 1));
        this.radius = 6 + (int)(Math.random() * ((20 - 6) + 1));
        this.deltaX = -10 + (int)(Math.random() * 21);
        this.deltaY = -10 + (int)(Math.random() * 21);
        this.maxBounces = 10 + (int)(Math.random() * ((25 - 10) + 1));
        this.mainWindow = mainWindow;
        thisBall = new Ellipse2D.Double(posX, posY, radius, radius);
    }
    public void draw(Graphics2D g2d){
            g2d.setColor(Color.RED);
            g2d.fill(thisBall);
            g2d.setColor(Color.BLACK);
            mainWindow.repaint();
    }
    public void run(){
        while(true){
            int oldx = (int) thisBall.getX();
            int oldy = (int) thisBall.getY();
            int newx = oldx + deltaX;
            if (newx + radius > 995 || newx <= 5){
               deltaX = -deltaX;
               bounces++;
            }   
            int newy = oldy+ deltaY;
            if (newy + radius > 795 || newy <= 5){ 
               deltaY = -deltaY; 
               bounces++;
            }
            thisBall.setFrame(newx, newy, radius, radius);
            this.posX = newx;
            this.posY = newy;
            mainWindow.repaint();
            if(bounces>=maxBounces){
                this.stop();
            }
            try {
                   Thread.sleep(30);
            }
            catch (InterruptedException e){  
                System.out.println("Woke up prematurely");
            }
        }
    }
    public int getPosX() {
        return posX;
    }
    public void setPosX(int posX) {
        this.posX = posX;
    }
    public int getPosY() {
        return posY;
    }
    public void setPosY(int posY) {
        this.posY = posY;
    }
}