Java join不等待线程退出

时间:2018-05-22 14:56:12

标签: java multithreading

我正在尝试同步这段代码:我想要的是Gioca等级直到类Gioco调用方法正常(罚款应该停止线程)但是当Gioca类调用run方法时它会在控制台上打印字符串“Fine”甚至可以说类Gioco还没有调用方法fine()。

   public class Gioca implements Runnable
    {
        private int vite;
        private int recuperi;

        public Gioca() 
        {
            vite=3;
            recuperi=0;
        }  


        public void gioca()
        {   
            Thread t=new Thread(new Gioco(vite));

            try 
            {       
                t.start();
                t.join();
            } 
            catch (Exception ex) {}
            System.out.println("Fine");
        }

        @Override
        public void run() 
        {
            gioca();    
        }
    }





public class Gioco extends Canvas implements ActionListener, KeyListener, Runnable
{
    private int direzione;
    private Timer timer;
    private JFrame f;
    private int vite;
    private int velocità;
    private int spazio;
    private Personaggio p;
    private int pos;
    private LinkedList<Ostacolo> o;
    private Random r; 
    private int po;

    private Image imm1=new ImageIcon(this.getClass().getResource("images/sfondo.jpg")).getImage();
    private Image imm2=new ImageIcon(this.getClass().getResource("images/cuore.png")).getImage();

    public Gioco(int vite)
    {
        r=new Random();

        try
        {
            File file=new File("images/punteggio.txt"); 
            Scanner scanner=new Scanner(file);
            spazio=scanner.nextInt();              
        } 
        catch (Exception e) {}
        direzione=3;
        this.vite=vite;
        o=new LinkedList();
        for(int i=0; i<20; i++)
            o.add(new Ostacolo(Math.abs(400*i)+1000));
        p=new Personaggio();
        this.velocità=2;
        timer=new Timer(10, this);      
        f=new JFrame("Gioco");
        f.setSize(1000, 700);
        f.setResizable(false);
        f.setLocation(200,200);
        f.add(this);
        f.addKeyListener(this);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    }  

    public void actionPerformed(ActionEvent ae) 
    {
        if(direzione==2)
        {
            velocità-=2;
            if(velocità<2)
                velocità=2;
        }

        if(direzione==1)
            p.setY(5);

        if(direzione==0)
            p.setY(-5);

        spazio+=velocità;

        if(spazio%1000<10)
            velocità++;

        pos=(pos+velocità)%4500;
        po=-pos;

        for(int i=0; i<20; i++)
        {
            o.get(i).muovi(velocità);
            if(o.get(i).getX()<-100)
            {
                o.remove(i);
                o.add(new Ostacolo(i*400));
            }
        }

        verificaCollisioni();
        repaint();

    }

    public void verificaCollisioni()
    {
        for(int i=0; i<20; i++)
        {
            if(o.get(i).getX()>300 && o.get(i).getX()<350)
            {
                int r[]=o.get(i).getDimensioni();
                if(r[0]<p.getY() && r[1]>p.getY())
                {

                }
                else
                    fine();
            }
        }
    }

    private void fine()
    {
        try
        {
            Thread.sleep(3000);
        }
        catch(Exception e){}

        timer.stop();

        try
        {            
            File file=new File("images/punteggio.txt");
            file.createNewFile();
            FileOutputStream f=new FileOutputStream(file);
            f.flush();
            String sPunteggio=String.valueOf(spazio);
            byte[] scrivi=sPunteggio.getBytes();
            f.write(scrivi);
        }
        catch(Exception e){}

        f.dispose();

    }

    @Override
    public void keyPressed(KeyEvent ke) 
    {
        int c=ke.getKeyCode();

        if(c == 40)
            direzione=1;
        if(c == 38)
            direzione=0;

        if(c==32)
            direzione=2;     
    }

    public void paint(Graphics g) 
    {
        Image workspace=createImage(getWidth(),getHeight());
        Graphics2D buffer=(Graphics2D) workspace.getGraphics();

        buffer.drawImage(imm1, po, 0, this);             

        buffer.setColor(new Color(242, 54, 33));
        buffer.setFont(new Font(Font.SANS_SERIF, Font.BOLD, 20));
        buffer.drawString(""+(spazio/100), 10, 20);   


        buffer.drawImage(imm2, 940, 4, this);
        buffer.setColor(new Color(13, 226, 13));
        buffer.drawString(""+vite, 920, 20);

        buffer.drawImage(p.getImage(), 300, p.getY(), this);

        for(int i=0; i<20; i++)
        {
            Ostacolo tmp=o.get(i);
            buffer.drawImage(tmp.getImage(), tmp.getX(),tmp.getY(), this);
        }

        Graphics2D g2=(Graphics2D)g;
        g2.drawImage(workspace, 0, 0, this);        
        buffer.dispose(); 
    } 

    public void update(Graphics g)
    {
        paint(g);
    }

    public void keyReleased(KeyEvent ke) {direzione=3;}
    public void keyTyped(KeyEvent ke) {}

    @Override
    public void run() 
    {
        f.setVisible(true);
        timer.start();

    }

}

此代码使用相同的说明,效果很好

public class Campana implements Runnable{    
    private String suono;
    private int volte;
    public Campana(String suono,int volte) 
    {
      this.suono =suono;  
      this.volte=volte;  
    }
    public void run() 
    {
       for(int i=0;i<volte;i++) {
         System.out.println((i+1)+" "+suono);

       }
    }   
}

public class Suona {

    public static void main(String args[]){

        Thread campana1=new Thread(new Campana("din", 5));                
        Thread campana2=new Thread(new Campana("don", 5));
        Thread campana3=new Thread(new Campana("dan", 5));
        try {
            campana1.start();
            campana1.join();
            campana2.start();
            campana2.join();
            campana3.start();
            campana3.join();




        } catch (InterruptedException ex) {
            Logger.getLogger(Suona.class.getName()).log(Level.SEVERE, null, ex);
        }


    }

}

1 个答案:

答案 0 :(得分:2)

在这种情况下,

t.join();等待run中的Gioco终止。该方法在

之后终止
f.setVisible(true);
timer.start();

已经完成,这将非常快,因为Timer将运行actionPerformed与调用timer.start();的线程不同的线程。它不会等到计时器停止。您可以通过在run方法中引入某种形式的同步来解决此问题。我不建议使用while循环,因为这会浪费资源来运行循环。相反,请考虑使用CountDownLatch (javadoc link)

将此添加到Gioco

private final CountDownLatch doneSignal = new CountDownLatch(1);

fine()致电doneSignal.countDown()结束时。最后将run()中的Gioco方法更改为以下内容:

@Override
public void run() 
{
    f.setVisible(true);
    timer.start();
    try {
        doneSignal.await();
    } catch (InterruptedException ex) {}//Logg this or something. Shouldn't really ever happen. 

}