同步方法究竟做了什么?

时间:2013-11-15 22:23:04

标签: java methods synchronized runnable

我正在使用Swing创建游戏。我将start()stop()同步,因为我被告知它更好。同步做什么以及使用它有什么好处?

我的代码:

import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;

import javax.swing.JFrame;

public class SpritePractice extends Canvas implements Runnable{

private JFrame frame;
private final static int WIDTH = 200, HEIGHT = 200;
private final static int SCALE = 2;
private final static Dimension dimens= new Dimension(WIDTH*SCALE, HEIGHT*SCALE);
private BufferedImage image;
private Graphics g;
private long nanoSecond = 1000000000;
private double tick = nanoSecond/60;
private boolean running = false;
private int pixelsFromImage[];
private int pixel[][];
private static DateFormat dateFormat = new SimpleDateFormat("[" + "yyyy/MM/dd HH:mm:ss"
        +"]");
private static DateFormat dateFormat2 = new SimpleDateFormat("[" + "HH:mm:ss" + "]");

public SpritePractice()
{
    frame = new JFrame("Bomberman");
    frame.setSize(dimens);
    frame.setMinimumSize(dimens);
    frame.setMaximumSize(dimens);
    frame.setResizable(false);
    frame.setLocationRelativeTo(null);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.add(this);
    frame.pack();
    frame.setVisible(true);
    init();
}
public void init()
{
    long startTime = System.nanoTime();
    Calendar cal = Calendar.getInstance();
    System.out.println("START: " + dateFormat.format(cal.getTime()));
    start();
}

public void run() 
{
    long now = System.nanoTime();
    long lastTick = System.nanoTime();
    long lastSecond = System.nanoTime();
    int frames = 0;

    while(running)
    {
        now = System.nanoTime();
        Calendar cal = Calendar.getInstance();

        if(now-lastTick >= tick)
        {
            lastTick = now;
            tick();
            render();
            frames++;
        }   
        if(now-lastSecond >= nanoSecond)
        {
            lastSecond = now;
            System.out.println(dateFormat2.format(cal.getTime()) + "FPS: " + frames);
            frames = 0;
        }
    }
}
public void tick()
{
    //updates values
}
public void render()
{
    BufferStrategy bs = getBufferStrategy();
    if(bs==null)
    {
        createBufferStrategy(2);
        return;
    }
    Graphics g = bs.getDrawGraphics();
    g.fillRect(0, 0, WIDTH*2, HEIGHT*2);
    g.dispose();
    bs.show();
    //renders graphics
}
public synchronized void start()
{
    running = true;
    run();
}
public synchronized void stop()
{
    running = false;
}
public static void main(String[] args)
{
    new SpritePractice();
}

}

5 个答案:

答案 0 :(得分:5)

进入synchronized方法的线程获取对拥有该方法的整个对象的锁定。

在您的特定情况下,您可以确保不会有两个并发线程同时执行start()stop()

阅读here有关同步方法的更多信息。

e.g。如果一个线程进入start()方法,它将在另一个线程进入stop()方法之前完成其执行。如果不同步这两种方法,可以进行以下连续:

- 主题1输入start()
- thread 1将布尔字段设置为true
- 线程2输入stop()
- 线程2将boolean字段设置为false
- 线程1执行run()方法

你绝对不想要。

答案 1 :(得分:2)

Java中的每个对象实例都有一个隐式互斥锁。在方法上同步等效于以下代码:

synchronized void foo() {
  // Some code here
}
void foo() {
  synchronized(this) {
    // Same code here
  }
}

净效应是当两个线程试图同时执行该代码块时,一个等待'synchronized'语句,直到另一个从块中出现。这确保了“这里的代码”部分一次只能在一个线程上运行。

答案 2 :(得分:2)

由于没有其他人用简单的英语解释过这个问题,我会:

将方法标记为“已同步”意味着您不希望多个线程同时访问该方法。如果你不希望你的代码允许所谓的“竞争条件”含义 - 再次用简单的英语 - “无论哪个线程首先到达这里,胜利”,这都很有用。

这是一个例子: 想象一下,一个简单的银行应用程序,可以重绘和存钱。如果您有三个线程运行 - 在一个小镇上放置3个ATM - 您希望所有三个线程(ATM)能够存入资金并同时从同一帐户重绘资金,如果需要的话。 p>

没有同步就会发生竞争条件。让我们来看看: 银行账户是100美元。 A人想存20美元。 B人愿意存入50美元。 C人想重绘130美元。如果人员A在人员B重绘之前存入人员B存款之前存款,则可以做到这一点。但这是抓住了!

在A人存款之前,账户上有100美元。存款方式可能如下所示:

// Naive deposit
public void deposit(double amount) {
    double currentAmount = getCurrentAmount(); // Critical
    setCurrentAmount(currentAmount + amount);
}

当A人存款时,ATM需要检索当前金额,加上该人想要存入的金额并将当前余额设置为该金额。然而,在临界点(标记为// Critial),B人也可以存入。如果ATM A(人员A的ATM)和ATM B(人员B的ATM)在同一时间存款,可以解决可能出现的问题:

  • ATM A检索当前金额。返还100美元。
  • ATM B检索当前金额。返还100美元。
  • ATM B将当前金额更新为$ 100 + $ 50 = $ 150。
  • ATM B存储150美元作为帐户的总金额。
  • ATM A,认为帐户只有100美元,将总余额更新为120美元。

有人刚刚损失30美元,因为ATM B在ATM A之前完成,在关键时刻!这就是“竞争条件” - 这都是谁先出现的问题。

现在转到synchronized关键字!此关键字对方法设置虚拟锁定,这意味着只有为此“锁定”提供“密钥”的线程(ATM)才能执行该代码。所有其他线程必须等待线程与这个神奇的“密钥”完成。在上面的银行示例中,这意味着ATM A将完成向账户存入20美元,之后ATM B可以检索当前金额并存入另外50美元。

答案 3 :(得分:0)

Synchronized允许正确的线程处理,这样Java就可以创建一个队列并处理你的应用程序可能跨越的不同线程,而不必担心它。

答案 4 :(得分:0)

stop()调用完成之前,您无法运行start()方法,反之亦然。 synchronized关键字在调用的同时,start()stop()方法中没有两个线程。{/ p>

换句话说,按下开始()按钮时,不允许按下停止()按钮直到开始完成。