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