Java 同步方法到底做什么?

Java 同步方法到底做什么?,java,methods,synchronized,runnable,Java,Methods,Synchronized,Runnable,我正在使用Swing创建一个游戏。我使start()和stop()同步,因为有人告诉我这样更好。synchronized做什么?使用它的优势是什么 我的代码: 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.BufferedIm

我正在使用Swing创建一个游戏。我使
start()
stop()
同步,因为有人告诉我这样更好。synchronized做什么?使用它的优势是什么

我的代码:

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();
}

}Synchronized允许正确的线程处理,通过这种方式,Java将创建一个队列并处理应用程序中可能跨越的不同线程,而无需担心。

在调用finished之前,您不能运行
stop()
方法。反之亦然
synchronized
关键字在调用的同时对
start()
stop()
方法中没有两个线程进行求积


换句话说,当您按下start()按钮时,在启动完成之前,不允许按下stop()按钮。

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

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

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

进入同步方法的线程将获得拥有该方法的整个对象的锁

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

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

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

--线程1进入
start()

--线程1将布尔字段设置为
true

--线程2进入
stop()

--线程2将
boolean
字段设置为
false

--线程1执行
run()
方法


这是你绝对不想要的。

既然没有人用简单的英语解释过,我会:

将方法标记为“synchronized”意味着您不希望多个线程同时访问该方法。如果你不想让你的代码允许所谓的“竞争条件”,这是很有用的——同样用简单的英语来说——“无论哪个线程先到达这里,都会赢”

下面是一个例子: 想象一下,一个简单的银行应用程序可以重新提取和存款。如果你有三个线程运行-3个ATM放在一个小镇上-你希望所有三个线程(ATM)能够在同一时间向/从同一个帐户存款和重新提取资金,如果需要的话

如果不同步,则会发生竞争情况。让我们看看: 银行存款是100美元。A想存20美元的人。B个人想存50美元。C个人想重画130美元。如果人员A在人员B存款之前存款(发生在人员C重画之前),则这是可能的。但问题是

在某人存款之前,账户上有100美元。存款方法可以如下所示:

// Naive deposit
public void deposit(double amount) {
    double currentAmount = getCurrentAmount(); // Critical
    setCurrentAmount(currentAmount + amount);
}
当某人存款时,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将在ATM B取回当前金额并再存入50美元之前完成向账户中存入20美元

你能把你的问题说得更具体些吗?在start方法中调用
run()
方法没有意义(至少对我来说),可能是
新线程(this).start()
?!并发性是一个复杂的主题。在使用多线程之前,您应该明确地了解您正在做什么。此程序不是线程安全的。幸运的是,它不会启动任何线程。因此,如果一个线程试图执行一个同步方法,而另一个同步方法尚未完成执行,那么同步这两个方法将确保第一个方法完全执行并完成,然后允许调用第二个方法的线程完全执行。只要他们尝试调用同一对象的方法。非常感谢,并感谢所有其他人的帮助!