我正在使用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();
}
}
答案 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)在同一时间存款,可以解决可能出现的问题:
有人刚刚损失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>
换句话说,按下开始()按钮时,不允许按下停止()按钮直到开始完成。