内存溢出问题+单例模式+自定义阻塞队列

ThreadLocal 使用:
1.set:将私有变量设置到线程
2.get:从线程中获取ThreadLocal
3.remove:将线程中的ThreadLocal移除。
4.initialValue:初始化
5.withInitialValue:初始化(lambda表达式)

使用场景:
1.解决线程安全问题
2.实现线程级别的数据传递

缺点:
1.不能进行父子线程之间的数据传递。
2.脏数据。ThreadLocal+线程池 (复用)
3.内存溢出

内存溢出问题

设置最大运行内存为5M
内存溢出问题+单例模式+自定义阻塞队列

package threadPool0523;

import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class ThreadPoolDemo20 {

    //1M大小的对象
    static class OOMObject{
        private byte[] bytes=new byte[1*1024*1024];
    }
    static ThreadLocal<OOMObject> threadLocal=new ThreadLocal<>();

    public static void main(String[] args) throws InterruptedException {
        ThreadPoolExecutor executor=new ThreadPoolExecutor(10,10,0, TimeUnit.SECONDS,
                new LinkedBlockingDeque<>());

        for (int i = 0; i <5 ; i++) {
            int finalI=i;
            executor.execute(new Runnable() {
                @Override
                public void run  () {
                    OOMObject oomObject=new OOMObject();
                    //set ThreadLocal
                    System.out.println("任务"+finalI+"执行了!");
                    threadLocal.set(oomObject);
                    //不用对象了
                    oomObject=null;
                }
            });
            //t.start();
            Thread.sleep(200);
        }
    }
}

内存溢出问题+单例模式+自定义阻塞队列

问题分析:
线程池是长生命周期的,而线程是执行完任务,线程就结束了(线程相关的资源都会被释放掉)。

内存溢出问题+单例模式+自定义阻塞队列
内存溢出问题+单例模式+自定义阻塞队列

面试题:
HashMap 和ThreadLocalMap处理哈希冲突的区别?
hashmap使用的是链表法,而ThreadLocalMap使用的是开放寻址法

为什么这么实现?
答:开放寻址法的特点和使用场景是数据量比价少的情况下,性能更好。
而hashmap里面存储的数据通常比较多,使用开放寻址法效率较低,最好使用链表法。

内存溢出问题+单例模式+自定义阻塞队列
内存溢出问题+单例模式+自定义阻塞队列
为什么将ThreadLocal中的key设置为弱引用?
为了最大长度的避免OOM

内存溢出问题+单例模式+自定义阻塞队列
解决ThreadLocal的内存溢出?
使用remove()。

提升程序性能:
1.多线程
2.单例模式

设计模式:
1.单例模式(手写)
2.工厂模式(简单工厂、抽象工厂)
3.模板模式

单例模式:
整个程序的运行中只存储一个对象

一:饿汉方式:直接创建对象(线程安全)

/**
 * 饿汉模式
 */
package ThreadDemo0603;
class Singleton{
    //1.创建一个私有的构造函数(防止其他类直接创建)
    private  Singleton(){
    }

    //2.定义私有变量(线程安全)
    private  static  Singleton singleton=new Singleton();

    //3.提供公共的获取实例的方法
    public static Singleton getInstance(){
        return singleton;
    }
}

public class ThreadDemo01 {

    public static void main(String[] args) {
        Singleton singleton=Singleton.getInstance();
        System.out.println(singleton);

    }
}

缺点:程序启动之后就被创建,有可能不会使用,从而浪费了系统资源。

懒汉方式:当程序启动之后并不会初始化,而是在什么时候调用什么时候再初始化

内存溢出问题+单例模式+自定义阻塞队列

内存溢出问题+单例模式+自定义阻塞队列

自定义阻塞队列: 链表 、数组

/**
 * 自定义阻塞队列
 */
package ThreadDemo0603;

import java.util.Random;

public class ThreadDemo06 {
    static class MyBlockingQueue{
        private int[] values;//实际存储数据的数组
        private int first;//队首
        private int last;//队尾
        private int size;//队列元素实际大小
        public MyBlockingQueue(int initial){
            //初始化变量
            values=new int[initial];
            first=0;
            last=0;
            size=0;

        }
        //添加元素(添加到队尾)
        public void offer(int val){
            synchronized (this){
                //判断是否存满
                if(size==values.length){
                    //队列满
                    try {
                        this.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                //添加元素到队尾
                values[last++]=val;
                size++;
                //判断是否为最后一个元素
                if(last==values.length){
                    last=0;
                }
                //尝试唤醒消费者
                this.notify();
            }
        }
        //查询方法
        public int poll(){
            int result=-1;
            synchronized (this){
                //判断边界值
                if(size==0){
                    //队列为空,阻塞等待
                    try {
                        this.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                //取元素
                result=values[first++];
                size--;
                //判断是否是最后一个元素
                if(first==values.length){
                    first=0;
                }
                //尝试唤醒生产者
                this.notify();
            }

            return result;
        }
    }

    public static void main(String[] args) {
        MyBlockingQueue myBlockingQueue=new MyBlockingQueue(100);
        Thread t1=new Thread(new Runnable() {
            @Override
            public void run() {
                //每隔500ms生产一条数据
                while(true){
                    int num=new Random().nextInt(10);
                    System.out.println("生成了随机数:"+num);
                    myBlockingQueue.offer(num);
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        t1.start();
        //创建消费者

        Thread t2=new Thread(new Runnable() {
            @Override
            public void run() {
                while(true){
                   int result=myBlockingQueue.poll();
                    System.out.println("消费了数据"+result);
                }
            }
        });
        t2.start();
    }
}

上一篇:ThreadLocal总结


下一篇:java面向对象程序设计第二版袁,冲刺7天拿下Offer!