我正在尝试同步此代码:我想要的是Gioca类一直等到Gioco类将方法调用为fine(精细应停止线程),但是当Gioca类调用run方法时,它将在控制台上打印字符串“很好”,甚至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);
        }


    }

}

最佳答案

在这种情况下,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.

}

09-18 01:14