Thread.748的javaFX多线程并发问题

最近在尝试用javafx写一个简单的2D游戏,没有仔细学过FX和多线程,就闭门造车一次。

在制作过程中,发现当移动射击等操作越来越多、主页面图形变化逐渐丰富的时候,开始出现卡顿,最后有概率地出现Not on java FX Application问题,接着出现NullPointerException导致程序崩溃。逐步排查后发现可能是并发问题,之前一直没有考虑到并发,而是简单地使用Platform.runlater(new Runnable(public void run{}))来解决Not on FX application的问题。

虽然无法确认,但是并发问题有最大的嫌疑性。

为了验证并解决问题,受数据库的启发,写了一个执行中心类(HandleCenter)

原理就是现将用数组存储起来,再进行批量依次操作。

我把每一次要进行图形变换的方法,例如

						   Platform.runLater(new Runnable() {
							   public void run() {
								   if(d.getId()==c.getId()) Main.pane.getChildren().remove(d);
							   }
						   });

直接看run的重写:在Main的pane里面直接删除Node d

解决:

把删除d的操作存储起来

PaintCenter.deleteBacth(d);

把所有的直接操作都替换成存储操作

然后在一个20L循环一次的线程里面执行批量操作:

   private class MoveContro extends Thread{
	   public void run() {
		   while(true) {
			   PaintCenter.excecuteBatch();
		   }
	   }
   }


最后发现问题被完美地解决了。


附上PaintCenter代码:

package com.Endemann.HandleCenter;

import java.util.ArrayList;

import com.Endemann.Controller.Controller01;
import com.Endemann.objects.Creature;

import javafx.scene.Node;
import javafx.scene.shape.Shape;
/**
 * @author Endemann
 * 2018/6/26
 *
 */
public class PaintCenter {
	private static ArrayList<Creature> addCreature    = new ArrayList<Creature>();
	private static ArrayList<Creature> deleteCreature = new ArrayList<Creature>();
	private static ArrayList<Shape>    addShape       = new ArrayList<Shape>();
	private static ArrayList<Shape>    deleteShape    = new ArrayList<Shape>();
	private static ArrayList<Node>     addNode        = new ArrayList<Node>();
	private static ArrayList<Node>     deleteNode     = new ArrayList<Node>();
	

	public static void addBatch(Node node) {
		addNode.add(node);
	}
	
	public static void addBatch(Creature c) {
		addCreature.add(c);
	}
	
	public static void addBatch(Shape shape) {
		addShape.add(shape);
	}
	
	public static void deleteBacth(Node node) {
		deleteNode.add(node);
	}
	
	public static void deleteBacth(Creature c) {
		deleteCreature.add(c);
	}
	
	public static void deleteBacth(Shape shape) {
		deleteShape.add(shape);
	}
	
	public static void excecuteBatch() {
		for(Creature c : addCreature)
			Controller01.Paint(c);	
		for(Creature c : deleteCreature)
			Controller01.Delete(c);
		for(Shape s : addShape)
			Controller01.Paint(s);
		for(Shape s : deleteShape)
			Controller01.Delete(s);
		for(Node n : addNode)
			Controller01.Paint(n);
		for(Node n : deleteNode)
			Controller01.Delete(n);
		addCreature.clear();
		deleteCreature.clear();
		addShape.clear();
		deleteShape.clear();
		addNode.clear();
		deleteNode.clear();
	}

}

但是这样做有可能在遍历ArrayList的时候,发生了ArrayList的更新而导致ArrayList异常。对此,可以这样解决:

执行方法内创建一个局部的ArrayList,把batch里面的所有元素对其进行赋值,再对这个ArrayList进行遍历。那么在对这个ArratList遍历的过程中就不会出现ArrayList的并发异常了。最后对存储操作的List进行removeAll操作,删除已经遍历过的元素。

附上按此思路来写的移动批量处理代码:

package com.Endemann.HandleCenter;

import java.util.ArrayList;
/**
 * @author Endemann
 * 2018/6/26
 */
public class MoveCenter {
	private static ArrayList<moveOperator> x = new ArrayList<moveOperator>();
	private static ArrayList<moveOperator> y = new ArrayList<moveOperator>();
	
	public static void X_addBatch(moveOperator mo) {
		x.add(mo);
	}
	public static void Y_addBatch(moveOperator mo) {
		y.add(mo);
	}
	public static void excecuteBatch() {
		ArrayList<moveOperator> tempX = new ArrayList<moveOperator>(x);
		for(moveOperator mo : tempX)
			if(mo!=null && mo.getCreature() != null)mo.getCreature().setTranslateX(mo.getd());
		
		ArrayList<moveOperator> tempY = new ArrayList<moveOperator>(y);
		for(moveOperator mo : tempY)
			if(mo!=null && mo.getCreature() != null)mo.getCreature().setTranslateY(mo.getd());
		
		x.removeAll(tempX);
		y.removeAll(tempY);
	}
}


 
 

猜你喜欢

转载自blog.csdn.net/weixin_40804987/article/details/80816277