最近在看head first 设计模式,学习了单例模式的使用,自己在实际编程中也经常使用这种设计模式。
在用swing练习编写贪吃蛇的小游戏的时候,打算将平时学习的东西运用到实际中去,发现了使用多线程很容易出错,对Java的多线程还是不熟悉啊。
贪吃蛇中玩家控制的蛇是唯一的,于是就把蛇这个类弄成了单例模式那样,然后再开一个线程控制蛇的移动。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class Snake {
private static Snake snake;
...
private Snake(){
...
new Thread(new Game()).start();
}

public static Snake getInstance() {
if(snake==null){
snake = new Snake();
System.out.println("test");
}
return snake;
}
...
}
public class Game implements Runnable {
@Override
public void run() {
Snake snake = Snake.getInstance();
if(snake.isrunning)
snake.update();
}
...
}

结果运行后控制台输出了多个test


出现这个现象我想到了多线程中snake不同步的问题,在Game这个线程中snake还没有被实例化,于是也new了一个对象出来,就有了两个Snake的对象,从而引发了问题,在head first 设计模式中说过,单例模式处理多线程的方法,利用双重检查加锁,首先检查是否实例已经创建了,如果尚未创建,“才”进行同步。这样一来,只有第一次会同步,减少使用同步,增加程序性能
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Snake {
private volatile static Snake snake;
...
public static Snake getInstance() {
if(snake==null){ //检查实例,如果不存在,就进入同步区块。
/*只有第一次才彻底执行这里的代码*/
synchronized (Snake.class){
if(snake==null) { //进入区块后,再检查一次,如果仍是null,才创建实例
snake = new Snake();
System.out.println("test");
}

}
return snake;
}
...
}

修改后正常运行

源码地址