JUC之ThreadLocal

ThreadLocal

在这里插入图片描述
ThreadLocal简介
在这里插入图片描述
在这里插入图片描述

代码演示

package com.aiguigu.juclearn.threadpool;

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

/**
 * @author: Runqiang_Jiang
 * @Time: 2024/3/16  15:11
 */
@Data
class House{
    int saleCount=0;


    public synchronized void saleHouse(){
        ++saleCount;
    }
//
//    ThreadLocal<Integer>  saleValues=new ThreadLocal<Integer>(){
//        @Override
//        protected Integer initialValue() {
//            return 0;
//        }
//    };
    ThreadLocal<Integer>  saleValues=ThreadLocal.withInitial(()->0);

    public void saleVolumety(){
        saleValues.set(saleValues.get()+1);
    }

}



public class ThreadLocalDemo {

    public static void main(String[] args) throws InterruptedException {
        House house = new House();

        for (int i = 0; i < 5; i++) {
            new Thread(()->{
                int size = new Random().nextInt(5) + 1;
//                System.out.println(size);
                for (int j = 0; j < size; j++) {
                    house.saleHouse();
                    house.saleVolumety();
                }
                System.out.println(Thread.currentThread().getName()+"\t"+"号卖出"+house.saleValues.get());
            }).start();
        }

        TimeUnit.MILLISECONDS.sleep(300);

        System.out.println(Thread.currentThread().getName()+"共计卖出:"+house.saleCount);
    }
}

在这里插入图片描述

在这里插入图片描述

   try{
//                System.out.println(size);
                   for (int j = 0; j < size; j++) {
                       house.saleHouse();
                       house.saleVolumety();
                   }
                   System.out.println(Thread.currentThread().getName()+"\t"+"号卖出"+house.saleValues.get());
               }finally {
                    house.saleValues.remove();
               }

线程池的例子

package com.aiguigu.juclearn.threadlocal;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * @author: Runqiang_Jiang
 * @Time: 2024/3/16  15:32
 */


class MyData{
    ThreadLocal<Integer> threadLocalValue=ThreadLocal.withInitial(()->0);

    public void add(){
        threadLocalValue.set(threadLocalValue.get()+1);
    }

}


public class ThreadLocalDemo2 {

    public static void main(String[] args) {
        ExecutorService threadPool = Executors.newFixedThreadPool(3);
        MyData myData = new MyData();
         try{
             for (int i = 0; i < 10; i++) {

                 threadPool.submit(()->{
                     Integer integer = myData.threadLocalValue.get();
                     myData.add();
                     Integer afterData = myData.threadLocalValue.get();
                     System.out.println(Thread.currentThread().getName()+"\t"+"beforeData:"+integer+"\t"+"afterData:"+afterData);
                 });
             }
         }catch (Exception e){
             e.printStackTrace();
         }
         finally {
             threadPool.shutdown();
         }
    }
}

如果不清空,值会变的越来越大
在这里插入图片描述
清空后

threadPool.submit(()->{
                   try{
                     Integer integer = myData.threadLocalValue.get();
                     myData.add();
                     Integer afterData = myData.threadLocalValue.get();
                     System.out.println(Thread.currentThread().getName()+"\t"+"beforeData:"+integer+"\t"+"afterData:"+afterData);
                   }finally {
                     myData.threadLocalValue.remove();
                   }
                 });

在这里插入图片描述
因为每个Thred内有自己的实例副本且该副本只由当前线程自己使用。既然其他Thred不可访问,那就不存在多线程间共享的问题。统一设置初始值,但是每个线程对这个值的修改都是各自线程互相独立的。
一句话:如何才能不争抢?
1.加入synchronized 或者Lock控制资源的顺序访问
2.人手一份,大家各自安好,没必要抢夺
ThreadLocal的源码分析

Thread、ThreadLocal以及ThreadLocalMap之间的关系
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
ThreadLocal的内存泄露问题

什么是内存泄漏?
不再被使用的对象或者变量占用的内存不能被回收,就是内存泄漏。
在这里插入图片描述
引用
在这里插入图片描述
强引用
在这里插入图片描述

package com.aiguigu.juclearn.reference;

/**
 * @author: Runqiang_Jiang
 * @Time: 2024/3/16  16:10
 */

class MyObject{

  //这个方法一般不用复写
  @Override
  protected void finalize() throws Throwable {
    System.out.println("----------invoke finalize method");
  }
}



public class ReferenceDemo {

  public static void main(String[] args) {
    MyObject myObject = new MyObject();

    System.out.println("gc before........"+myObject);

    myObject=null;

    System.gc();//人为

    System.out.println("gc after........"+myObject);

  }
}

在这里插入图片描述
软引用
在这里插入图片描述

public static void main(String[] args) {

    SoftReference<MyObject> softReference = new SoftReference<>(new MyObject());
    System.out.println("-----softRererence"+softReference.get());
    System.gc();
    System.out.println("----------gc after内存够用:"+softReference.get());

    byte[] bytes = new byte[20 * 1024 * 1024];

    System.out.println("----------gc after内存不够用:"+softReference.get());


  }

在这里插入图片描述
虚引用
在这里插入图片描述

public static void main(String[] args) {

    WeakReference<MyObject> weakReference = new WeakReference<>(new MyObject());
    System.out.println("-----gc before:  "+weakReference.get());

    System.gc();

    System.out.println("-----gc after:  "+weakReference.get());


  }

在这里插入图片描述
在这里插入图片描述
虚引用
在这里插入图片描述
代码

 public static void main(String[] args) {
    MyObject myObject = new MyObject();
    ReferenceQueue<MyObject> referenceQueue = new ReferenceQueue<>();
    PhantomReference<MyObject> phantomReference = new PhantomReference<>(myObject,
        referenceQueue);
    //System.out.println(phantomReference.get());

    List<byte[]> bytes=new ArrayList<>();


    new Thread(()->{
      while (true){
        bytes.add(new byte[1*1024*1024]);
        try {
          TimeUnit.MILLISECONDS.sleep(500);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
        System.out.println(phantomReference.get()+"\t"+"list add success");
      }
    },"t1").start();

    new Thread(()->{
      while (true){
        Reference<? extends MyObject> poll = referenceQueue.poll();
        if(poll!=null){
          System.out.println("有虚对象被回收,加入了队列");
          break;
        }
      }
    },"t2").start();


  }

在这里插入图片描述

GCroots和四大引用小结
在这里插入图片描述
关系
在这里插入图片描述
在这里插入图片描述
为什么要用弱引用?

在这里插入图片描述
在这里插入图片描述
当前栈帧出栈,当前栈帧对应的threadlocal对象也应当被销毁,如果是强引用,该threadlocal对象就不会被回收,从而发生内存泄漏,从而key与threadlocal对象为弱引用。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
总结

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 9
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值