java位移实现原理_java通过位移操作实现状态打标

二进制是用0,1 两个数表示的,这两个数当然也可以表示两种状态。

场景:有4个线程处理一个任务。需要监控每个线程的处理状态,已经执行的线程不能重复执行,当然我们可以在表中建立4个字段,分别对应一个线程,初始状态为0,执行成功则为1,但这样字段多而且更大的隐患在于没有扩展性,状态字段与线程数是紧藕合的。如果新增一个线程,则要新增一个状态字段,其实用二进制+位移进行状态打标,只需要一个字段就可以达到目的。

有如下表格

线程名称

状态初始值

状态成功值

0

0

0000 0001

1

0

0000 0010

2

0

0000 0100

3

0

0000 1000

文字表达有点无力,直接上代码:

package common.statusProcess;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import java.util.stream.IntStream;

/**

* @desc 状态处理工具类

* @author kanggw

* @datetime 2020/6/2,5:33 下午

*/

public class StatusProcessUtil {

/**

* check当前块是否已经成功执行过

* @param status 当前块的状态值

* @param partId 块号

* 校验规则:

* 修改处使用了对1进行左移的操作, 1<< 块号,目的是使用二进制来表示不同分块的状态,如

* 0块 则为 0000 0001

* 1块 则为 0000 0010

* 2块 则为 0000 0100

* 3块 则为 0000 1000

*

* 1代表完成

*

* 校验时同样对1进行左移 1<< 块号。 然后将状态与 n 进行按位与操作,这样执行过的状态就能被识别出来

*

* @return

*/

public static boolean checkPartIdSuccess(int status,int partId){

int n = 1<< partId;

int m = status & n;

return n==m;

}

/**

* 根据分块数得出完成状态的值。1左移n位,来表示分片n的完成

* @param partCount 分片总数

* @return

*/

public static int toSuccessStatus(int partCount){

int status = 0;

for (int i=0;i

status += 1<

}

return status;

}

public static void main(String args[]){

// // 0000 0001

// System.out.println(StatusProcessUtil.toSuccessStatus(1));

// //0000 0011

// System.out.println(StatusProcessUtil.toSuccessStatus(2));

// //0000 0111

// System.out.println(StatusProcessUtil.toSuccessStatus(3));

// //0000 1111

// System.out.println(StatusProcessUtil.toSuccessStatus(4));

//所有线程都执行成功的状态值(模拟有4个线程)

final int allSuccess = toSuccessStatus(4);

System.out.println("全部线程都执行成功的状态值:" + Integer.toBinaryString(allSuccess));

final ExecutorService executorService = Executors.newFixedThreadPool(4);

final StatusTable statusTable = new StatusTable();

IntStream.range(0,4).forEach(partId -> {

executorService.execute(() -> {

Thread.currentThread().setName(String.valueOf(partId));

//模拟处理两次

IntStream.rangeClosed(1,2).forEach(item -> {

//检查该线程是否处理成功

int part = Integer.parseInt(Thread.currentThread().getName());

final boolean b = checkPartIdSuccess(statusTable.getStatus(), part);

if (!b) {

System.out.println("线程:"+Thread.currentThread().getName() +" ,第"+item + " 次处理,开始执行");

final int i = 1 << Integer.parseInt(Thread.currentThread().getName());

statusTable.setStatus(statusTable.getStatus() + i);

} else {

System.out.println("线程:"+Thread.currentThread().getName() +" ,第"+item + " 次处理,已经执行过");

}

});

//以二进制形式输出

System.out.println("状态结果输出,线程"+ Thread.currentThread().getName() +":" + Integer.toBinaryString(statusTable.getStatus()));

});

});

executorService.shutdown();

}

/**

* @desc 模拟状态表

* @author kanggw

* @datetime 2020/6/2,5:46 下午

*/

static class StatusTable{

private int status = 0;

public int getStatus() {

return status;

}

public void setStatus(int status) {

this.status = status;

}

}

}

随机结果输出:

全部线程都执行成功的状态值:1111

线程:0 ,第1 次处理,开始执行

线程:1 ,第1 次处理,开始执行

线程:2 ,第1 次处理,开始执行

线程:3 ,第1 次处理,开始执行

线程:2 ,第2 次处理,已经执行过

线程:1 ,第2 次处理,已经执行过

线程:0 ,第2 次处理,已经执行过

状态结果输出,线程1:1111

状态结果输出,线程2:1111

线程:3 ,第2 次处理,已经执行过

状态结果输出,线程0:1111

状态结果输出,线程3:1111

其实写这么多中心思想就只有一个,那就是通过二进制来进行状态标识,如果您有涉及到状态的相关场景,不妨考虑下能不能通过这种方式来解决,这样可以为表节省一些字段。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值