美文网首页
java通过位移操作实现状态打标

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

作者: 内沐 | 来源:发表于2020-06-02 20:28 被阅读0次

    二进制是用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<partCount;i++){
                status += 1<<i;
            }
            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

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

    相关文章

      网友评论

          本文标题:java通过位移操作实现状态打标

          本文链接:https://www.haomeiwen.com/subject/dbqpzhtx.html