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();
}
}