ThreadLocal-案例编码实战

本文通过案例探讨了ThreadLocal在多线程环境中的应用,从最初的数据共享问题到后来的独立统计需求,展示了ThreadLocal如何确保每个线程拥有自己的变量副本,避免了线程间的资源争抢。通过使用ThreadLocal,可以实现线程安全的独立计数,无需额外的同步控制。
摘要由CSDN通过智能技术生成

问题描述:5个销售买房子,集团只关心销售总量的准确统计数,按照总销售额统计,方便集团公

司给部分发送奖金--------群雄逐鹿起纷争------为了数据安全只能加锁

/**
 * 需求:5个销售卖房子,集团只关心销售总量的精确统计数
 */
package com.nanjing.gulimall.zhouyimo.test;

import java.util.Random;
import java.util.concurrent.TimeUnit;

/**
 * @author zhou
 * @version 1.0
 * @date 2024/3/17 9:43 下午
 */
public class ThreadLocalDemo {
    public static void main(String[] args) {
        House house = new House();
        for (int i = 1; i <= 5; i++) {
            new Thread(() -> {
                int size = new Random().nextInt(5) + 1;
                System.out.println(size);
                for (int j = 1; j <= size; j++) {
                    house.saleHouse();
                }
            }, String.valueOf(i)).start();

        }
        try {
            TimeUnit.MILLISECONDS.sleep(300);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + "\t" + "共计卖出多少套: " + house.saleCount);
    }

}


class House {
    int saleCount = 0;

    public synchronized void saleHouse() {
        saleCount++;
    }
}

4
5
3
4
4
main	共计卖出多少套: 20

需求变更:希望各自分灶吃饭,各凭销售本事提成,按照出单数各自统计-------比如房产中介销售

都有自己的销售额指标,自己专属自己的,不和别人参和。----人手一份天下安

/**
 * 需求:需求变更:希望各自分灶吃饭,各凭销售本事提成,按照出单数各自统计-------比如房产中介销售都有自己的销售额指标,自己专属自己的,不和别人参和。
 */
package com.nanjing.gulimall.zhouyimo.test;

import java.util.Random;
import java.util.concurrent.TimeUnit;

/**
 * @author zhou
 * @version 1.0
 * @date 2024/3/17 9:43 下午
 */
public class ThreadLocalDemo {
    public static void main(String[] args) {
        House house = new House();
        for (int i = 1; i <= 5; i++) {
            new Thread(() -> {
                int size = new Random().nextInt(5) + 1;
                for (int j = 1; j <= size; j++) {
                    house.saleHouse();
                    house.saleVolumnByThreadLocal();
                }
                System.out.println(Thread.currentThread().getName() + "\t" + "号销售卖出:" + house.saleVolume.get());
            }, String.valueOf(i)).start();

        }
        try {
            TimeUnit.MILLISECONDS.sleep(300);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + "\t" + "共计卖出多少套: " + house.saleCount);
    }

}


class House {
    int saleCount = 0;

    public synchronized void saleHouse() {
        saleCount++;
    }

    /*ThreadLocal<Integer> saleVolume = new ThreadLocal<Integer>(){
        @Override
        protected Integer initialValue() {
            return 0;
        }
    };*/
    //上面匿名内部类写的非常繁琐,可以使用ThreadLocal.withInitial()简化
    ThreadLocal<Integer> saleVolume = ThreadLocal.withInitial(() -> 0);

    public void saleVolumnByThreadLocal() {
        int volumn = saleVolume.get();
        volumn++;
        saleVolume.set(volumn);
    }
}


1	号销售卖出:5
2	号销售卖出:5
3	号销售卖出:3
4	号销售卖出:2
5	号销售卖出:4
main	共计卖出多少套: 19

总结

因为每个Thread内有自己的实例副本且该副本只有当前线程自己使用

既然其他ThreadLocal不可访问,那就不存在多线程间共享问题

统一设置初始值,但是每个线程对这个值得修改都是各自线程互相独立得

如何才能不争抢

  • 加入synchronized或者Lock控制资源的访问顺序
  • 人手一份,大家各自安好,没有必要争抢

改进:

package com.nanjing.gulimall.zhouyimo.test;

import java.util.Random;
import java.util.concurrent.TimeUnit;

/**
 * @author zhou
 * @version 1.0
 * @date 2024/3/17 9:43 下午
 */
public class ThreadLocalDemo {
    public static void main(String[] args) {
        House house = new House();
        for (int i = 1; i <= 5; i++) {
            new Thread(() -> {
                try {
                    int size = new Random().nextInt(5) + 1;
                    for (int j = 1; j <= size; j++) {
                        house.saleHouse();
                        house.saleVolumnByThreadLocal();
                    }
                    System.out.println(Thread.currentThread().getName() + "\t" + "号销售卖出:" + house.saleVolume.get());
                } finally {
                    house.saleVolume.remove();
                }
            }, String.valueOf(i)).start();

        }
        try {
            TimeUnit.MILLISECONDS.sleep(300);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + "\t" + "共计卖出多少套: " + house.saleCount);
    }

}


class House {
    int saleCount = 0;

    public synchronized void saleHouse() {
        saleCount++;
    }

    /*ThreadLocal<Integer> saleVolume = new ThreadLocal<Integer>(){
        @Override
        protected Integer initialValue() {
            return 0;
        }
    };*/
    //上面匿名内部类写的非常繁琐,可以使用ThreadLocal.withInitial()简化
    ThreadLocal<Integer> saleVolume = ThreadLocal.withInitial(() -> 0);

    public void saleVolumnByThreadLocal() {
        /*int volumn = saleVolume.get();
        volumn++;
        saleVolume.set(volumn);*/
        //或者
        saleVolume.set(saleVolume.get() + 1);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ZHOU_VIP

您的鼓励将是我创作最大的动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值