生命游戏 Java版 10万长度的数组实现 串性加并行实现

初次运行如果遇到Exception in thread "main" java.lang.OutOfMemoryError: Java heap space问题

参考https://blog.csdn.net/litaoshoujiao/article/details/8165429这种类型的文章

我参数设置了-Xmx4096m就没问题了

第二次更新这篇文章了,将原来代码中不正确的地方进行了修改,速度相比上一个版本有了提升,会继续更新

 

串性版(今天又发现了代码里的小错误,改好了。。。)

package game_of_life;

public class Plate {
	private int length;
	private int[][] plate;
	
	public Plate(int length) {
		this.length = length;
		int width = (int) Math.ceil((double)length / 32); 
		plate = new int[length][width];
		init();
	}
	
	public void init() {
		for(int i = 0; i < plate.length; i ++) {
			for (int j = 0; j < plate[0].length; j++) {
				plate[i][j] = (int)(Math.random() * Integer.MAX_VALUE);
			}
		}
	}
	
	/**
	 * 细胞周期状态转换
	 */
	public void transfrom() {
		int[][] nextMatrix=new int[plate.length][plate[0].length];
		for (int x = 0; x < nextMatrix.length; x++) {
			for (int y = 0; y < nextMatrix.length; y++) {
				int num = getLivedNum(x, y);
				int value = 0;
				if (num == 3) {
					value = 1;
				}else {
					if (num == 2) {
						value = getValue(x, y);
					}
				}
				setValue(nextMatrix, x, y, value);
			}
		}
		plate = nextMatrix;
	}
	
	
	/**
	 * 获取指定坐标位置的值,0或1
	 * index 是当前坐标位置映射到 plate数组中时 的 列下标
	 * offset 是当前的坐标位置映射到 int数组中时, 在int元素中从高位到低位的偏移量
	 * node 是(x,y)映射到int数组中的对应元素的值
	 *  因为是在这个程序里,要将1个int值转化成32位来使用,所以需要从二进制的角度来看待这个int值,即node值
	 *  我们要取的是node里的某一位,所以要将那一位 左移(32 - offset),再与1,这样就能得到那一位的值了
	 *  为什么是(32 - offse)呢? 因为从逻辑上来看,一个数组中的元素,它左边是高位,右边是低位,所以左移再与1会更简单
	 *  思维上也更清晰一些
	 * 下面是一个例子
	 *  假设node=10101010 10101010 10101010 10101010,offset=3;
	 *           ^
	 *           |
	 *         这一位就是offset定位到的那一位的值,我们要得到这个值
	 * node需要左移(32 - 3)= 29 位,node左移29位之后为:00000000 00000000 00000000 00000101
	 * node和1相与
	 * 		00000000 00000000 00000000 00000101
	 * 		00000000 00000000 00000000 00000001
	 * & ——————————————————————————————————————————
	 * 		00000000 00000000 00000000 00000001
	 * @param x 行
	 * @param y 列
	 * @return
	 */
	public int getValue(int x, int y) {
		//获取当前坐标在 plate数组中的 列下标
		int index = y / 32;
		//算偏移量
		int offset = y % 32 + 1;
		//获取映射的plate数组中的值
		int node = plate[x][index];
		//将获取的int值,左移(32 - offset)位,再与1,就能得到 下,(x,y)映射到int数组中的某个元素的第n位的值了
		int value = node >>> (32 - offset) & 1;
		return value;
	}
	/**
	 * correction是修正值,将correction右移进行扩展,
	 * 因为new一个nextMatrix时,它的初始值是0,所以当要写入nextMatrix数组中(x, y)位置的值为0时,就什么都不用做
	 * 当要写入的值为1时,则将修正值与原值进行 “或运算”,则能将源位置的0修改成1
	 * 下面是一个例子
	 * 假设node = nextMatrix[x][index],newValue = 1
	 * 假设node=10000000 00000000 00000000 00000000,offset=3;
	 *            ^
	 *            |
	 *         这一位就是offset定位到的那一位的值,我们要修改这个值
	 * correction初始值为1
	 * correction需要右移(32 - 3)= 29 位,correction右移29位之后为:00100000 00000000 00000000 00000000
	 * node或correction
	 * 		10000000 00000000 00000000 00000000
	 * 	或	00100000 00000000 00000000 00000000
	 * ————————————————————————————————————————————
	 * 		10100000 00000000 00000000 00000000
	 * 
	 * @param nextMatrix	下一代的数组
	 * @param x	行
	 * @param y	列
	 * @param newValue
	 */
	public void setValue(int[][] nextMatrix, int x, int y, int newValue) {
		
		if(newValue != 0) {
			int index = y / 32;
			int offset = y % 32 + 1;
			int correction = 1;
			correction <<= (32 - offset);
			nextMatrix[x][index] |= correction;
		}
	}
	
	/**
	 * 统计细胞周围的活细胞的数量
	 * @param x
	 * @param y
	 * @return
	 */
	public int getLivedNum(int x, int y) {
		
		int num = 0;
		
		//左边
        if(y!=0){
            num+=getValue(x, y - 1);
        }
        //左上角
        if(x!=0&&y!=0){
        	num+=getValue(x - 1, y - 1);
        }
        //上边
        if(x!=0){
        	num+=getValue(x - 1, y);
        }
        //右上
        if(y!=length-1&&x!=0){
        	num+=getValue(x - 1, y + 1);
        }
        //右边
        if(y!=length-1){
        	num+=getValue(x, y + 1);
        }
        //右下
        if(x!=length-1&&y!=length-1){
        	num+=getValue(x + 1, y + 1);
        }
        //下边
        if(x!=length-1){
        	num+=getValue(x + 1, y);
        }
        //左下
        if(y!=0&&x!=length-1){
        	num+=getValue(x + 1, y - 1);
        }
        return num;
	}
	
	
    public void show() {
    	for (int i = 0; i < plate.length; i++) {
			for (int j = 0; j < plate.length; j++) {
				System.out.print(getValue(i, j) + " ");
			}
			System.out.println();
		}
    }
    
    public static void main(String[] args) {
		long start = System.currentTimeMillis();
		Plate plate = new Plate(100000);
//		plate.show();
		plate.transfrom();
		long end = System.currentTimeMillis();
		System.out.println("一代状态转化时间:" + ((end - start)/1000.000) + "s");
	}
}

并行版

package game_of_life;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ParallelGameLife {

	private int threadCount;			//线程数
	private CyclicBarrier barrier;		//障栅
	private ExecutorService pool;		//线程池
	
	private int conversions;			//进化的代数
	private int length;					//数组长度
	private int[][] plate;				//当前的细胞数组
	private int[][] nextMatrix;			//下一代的细胞数组
	private boolean isCovered = false;
	
	public ParallelGameLife(int length, int conversions, int threadCount) {
		this.length = length;
		this.conversions = conversions;
		this.threadCount = threadCount;
		barrier = new CyclicBarrier(threadCount);
		pool = Executors.newFixedThreadPool(threadCount);
		int width = (int) Math.ceil((double)length / 32); 
		plate = new int[length][width];
		nextMatrix = new int[length][width];
		init();
	}
	
	public void init() {
		long start = System.currentTimeMillis();
		for(int i = 0; i < plate.length; i ++) {
			for (int j = 0; j < plate[0].length; j++) {
				plate[i][j] = (int)(Math.random() * Integer.MAX_VALUE);
			}
		}
		long end = System.currentTimeMillis();
		System.out.print("初始化结束, ");
		System.out.println("用时: " + ((end - start) / 1000.000) + "s");
	}
	
	public void work() {
		long start = System.currentTimeMillis();
		int from = 0;
		int interval = plate.length / threadCount;
		int to = interval;
		for (int i = 0; i < threadCount; i++) {
			if (to >= plate.length) {
				to = plate.length - 1;
			}
			pool.submit(new convertor(from, to));
			from = to + 1;
			to += interval;
		}
		pool.shutdown();
		while(!pool.isTerminated());
		long end = System.currentTimeMillis();
		System.out.println("进化" + conversions + "代耗时:" + ((end - start)/1000.000) + "秒");
	}
	
	public class convertor implements Runnable{
		
		int from;
		int to;
		
		public convertor(int from, int to) {
			this.from = from;
			this.to = to;
		}
		

		@Override
		public void run() {
			for (int i = 0; i < conversions; i++) {
				isCovered = false;
				transfrom(from, to);
				try {
					barrier.await();
				} catch (InterruptedException e) {
					e.printStackTrace();
				} catch (BrokenBarrierException e) {
					e.printStackTrace();
				}
				synchronized (this) {
					if (!isCovered) {
						plate = nextMatrix;
						nextMatrix = new int[length][plate[0].length];
						isCovered = true;
					}
				}
			}
		}
		
	}

	/**
	 * 细胞周期状态转换
	 */
	public void transfrom(int from, int to) {
		for (int x = from; x <= to; x++) {
			for (int y = 0; y < plate.length; y++) {
				int num = getLivedNum(x, y);
				int value = 0;
				if (num == 3) {
					value = 1;
				} else {
					if (num == 2) {
						value = getValue(x, y);
					}
				}
				setValue(nextMatrix, x, y, value);
			}
		}
	}
	/**
	 * correction是修正值,将correction右移进行扩展,
	 * 因为new一个nextMatrix时,它的初始值是0,所以当要写入nextMatrix数组中(x, y)位置的值为0时,就什么都不用做
	 * 当要写入的值为1时,则将修正值与原值进行 “或运算”,则能将源位置的0修改成1
	 * 下面是一个例子
	 * 假设node = nextMatrix[x][index],newValue = 1
	 * 假设node=10000000 00000000 00000000 00000000,offset=3;
	 *            ^
	 *            |
	 *         这一位就是offset定位到的那一位的值,我们要修改这个值
	 * correction初始值为1
	 * correction需要右移(32 - 3)= 29 位,correction右移29位之后为:00100000 00000000 00000000 00000000
	 * node或correction
	 * 		10000000 00000000 00000000 00000000
	 * 	或	00100000 00000000 00000000 00000000
	 * ————————————————————————————————————————————
	 * 		10100000 00000000 00000000 00000000
	 * 
	 * @param nextMatrix	下一代的数组
	 * @param x	行
	 * @param y	列
	 * @param newValue
	 */
	public void setValue(int[][] nextMatrix, int x, int y, int newValue) {
		
		if(newValue != 0) {
			int index = y / 32;
			int offset = y % 32 + 1;
			int correction = 1;
			correction <<= (32 - offset);
			nextMatrix[x][index] |= correction;
			
		}
	}

	/**
	 * 获取指定坐标位置的值,0或1 index 是当前坐标位置映射到 plate数组中时 的 列下标 offset 是当前的坐标位置映射到 int数组中时,
	 * 在int元素中从高位到低位的偏移量 node 是(x,y)映射到int数组中的对应元素的值
	 * 因为是在这个程序里,要将1个int值转化成32位来使用,所以需要从二进制的角度来看待这个int值,即node值
	 * 我们要取的是node里的某一位,所以要将那一位 左移(32 - offset),再与1,这样就能得到那一位的值了 为什么是(32 - offse)呢?
	 * 因为从逻辑上来看,一个数组中的元素,它左边是高位,右边是低位,所以左移再与1会更简单 思维上也更清晰一些 下面是一个例子 假设node=10101010
	 * 10101010 10101010 10101010,offset=3; ^ | 这一位就是offset定位到的那一位的值,我们要得到这个值
	 * node需要左移(32 - 3)= 29 位,node左移29位之后为:00000000 00000000 00000000 00000101
	 * node和1相与
	 * 		00000000 00000000 00000000 00000101
	 * 		00000000 00000000 00000000 00000001
	 * & ——————————————————————————————————————————
	 * 		00000000 00000000 00000000 00000001 
	 * @param x 行
	 * @param y 列
	 * @return
	 */
	public int getValue(int x, int y) {
		// 获取当前坐标在 plate数组中的 列下标
		int index = y / 32;
		// 算偏移量
		int offset = y % 32 + 1;
		// 获取映射的plate数组中的值
		int node = plate[x][index];
		// 将获取的int值,左移(32 - offset)位,再与1,就能得到 下,(x,y)映射到int数组中的某个元素的第n位的值了
		int value = node >>> (32 - offset) & 1;
		return value;
	}
	/**
	 * 统计细胞周围的活细胞的数量
	 * 
	 * @param x
	 * @param y
	 * @return
	 */
	public int getLivedNum(int x, int y) {

		int num = 0;

		// 左边
		if (y != 0) {
			num += getValue(x, y - 1);
		}
		// 左上角
		if (x != 0 && y != 0) {
			num += getValue(x - 1, y - 1);
		}
		// 上边
		if (x != 0) {
			num += getValue(x - 1, y);
		}
		// 右上
		if (y != length - 1 && x != 0) {
			num += getValue(x - 1, y + 1);
		}
		// 右边
		if (y != length - 1) {
			num += getValue(x, y + 1);
		}
		// 右下
		if (x != length - 1 && y != length - 1) {
			num += getValue(x + 1, y + 1);
		}
		// 下边
		if (x != length - 1) {
			num += getValue(x + 1, y);
		}
		// 左下
		if (y != 0 && x != length - 1) {
			num += getValue(x + 1, y - 1);
		}
		return num;
	}
	
	public void show() {
    	for (int i = 0; i < plate.length; i++) {
			for (int j = 0; j < plate.length; j++) {
				System.out.print(getValue(i, j) + " ");
			}
			System.out.println();
		}
    }
    public static void main(String[] args) {
		ParallelGameLife game = new ParallelGameLife(100000, 1, Runtime.getRuntime().availableProcessors());
		game.work();
	}
}

 

  • 2
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值