juc 入门

 

public static void main(String[] args) throws ExecutionException, InterruptedException, TimeoutException {
        // 创建3个定长线程池
        ExecutorService executorService = Executors.newFixedThreadPool(3);
        // 创建线程 缺点 api少
        FutureTask<String> futureTask = new FutureTask<>(() -> {
            try {
                sleep(300);
                System.out.println(1);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }, "花生");
        FutureTask<String> futureTask1 = new FutureTask<>(() -> {
            try {
                sleep(300);
                System.out.println(2);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }, "花生");
        FutureTask<String> futureTask2 = new FutureTask<>(() -> {
            try {
                sleep(300);
                System.out.println(3);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }, "花生");
        // 将线程放入线程池中
        executorService.submit(futureTask);
        executorService.submit(futureTask1);
        executorService.submit(futureTask2);
        // 获取线程返回值 会一直阻塞状态 get 会抛出异常处理
        System.out.println(futureTask.get());
        // 通过 isDone 方法判断是否处理
        if (futureTask.isDone()) {
        // 通过get 传入等待时间 超过等待时间 直接报错 判定方法 futureTask.get(
3, TimeUnit.SECONDS); } }

实际案例 :

/**
     * 未使用异步时间 会在31秒 使用 流+异步线程 5.1秒 大大提升效率
     * @param args
     * @throws ExecutionException
     * @throws InterruptedException
     * @throws TimeoutException
     */
    public static void main(String[] args) throws ExecutionException, InterruptedException, TimeoutException {
        // 淘宝 天猫 京东 少少 阿里  查询一个产品 并返回一个价格集合  采用异步多线程 处理问题 提高效率
        long begin = System.currentTimeMillis();
        List<String> list = Arrays.asList("淘宝", "淘宝", "天猫", "京东", "少少", "阿里");
        //  通过流的方式 通过异步函数 调用获取价格 通过map 映射成CompletableFuture 放回 list<CompletableFuture> 集合  然后在流的方式 从CompletableFuture.join 获取结果  放回结果集
        List<BigDecimal> collect = list.stream().map(s -> CompletableFuture.supplyAsync(() -> getPrice(s))).collect(Collectors.toList()).stream().map(CompletableFuture::join).collect(Collectors.toList());
        System.out.println(System.currentTimeMillis()-begin);
        System.out.println(collect);
    }


    private static BigDecimal getPrice(String name){
        try {
            // 时间类 睡眠5秒
            TimeUnit.SECONDS.sleep(5);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        // ThreadLocalRandom.current() 真正随机数字 通过 BigDecimal 转换并保留两位小数 四舍五入
        return BigDecimal.valueOf(ThreadLocalRandom.current().nextDouble(100)).setScale(2, RoundingMode.UP);
    }

completableFuture 的 常用方法解析

 /**
     * 常用方法 介绍
     *
     * @param args
     * @throws ExecutionException
     * @throws InterruptedException
     * @throws TimeoutException
     */
    public static void main(String[] args) throws ExecutionException, InterruptedException, TimeoutException {
        // 创建 定长 线程池
        ExecutorService executorService = Executors.newFixedThreadPool(1);
        CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> "张三", executorService);
        // 需要截获异常 阻塞 一直等待拿到结果
        completableFuture.get();
        // 需要截获异常 设定等待时间 超过等待时间 直接报错 判定计算失败
        completableFuture.get(3, TimeUnit.SECONDS);
        // 无异常  一直等待结果
        completableFuture.join();
        // 无异常  如果计算完成 返回结果 未计算完成则返回设定的值 ->返回信息"
        completableFuture.getNow("返回信息");
        // 计算完成 则返回 true  不打算 方法join 返回计算结果
        // 计算未完成 打断计算方法 返回false join返回设定返回值 ->dd
        completableFuture.complete("dd");
        completableFuture.join();
        // 对计算结果串行话 ,thenApply里面方法依赖上个方法结果 依次传递 不修改原属性值 需要从新获取新值
        // 中间步骤错误 则停止
        String join = completableFuture.thenApply(v -> v + "11").thenApply(v -> v + "22").join();
        System.out.println(join);
        // 计算结果 串行 结果处理
        completableFuture.whenComplete((v, e) -> {
            if (e == null) System.out.println(v);
            //计算结果 串行 异常拦截处理
        }).exceptionally(e -> {
            System.out.println(e.getMessage());
            return e.getMessage();
        });
        // 当放中间步骤发生异常不会终止,会一直计算 异常问题 数值会丢失
        completableFuture.handle((f, e) -> {
            int i = 10 / 0;
            // 异常 代码无法执行 失效
            System.out.println(f);
            return e + "111";
        }).handle((f, e) -> {
            // 上一方法 异常返回值为null
            System.out.println(f);
            //  此时 f=null  返回结果为 null2222
            return f + "2222";
        }).whenComplete((f, e) -> {
            System.out.println(f);
            if (e != null) System.out.println(e.getMessage());
        });
        // 消费类型 接参数 无返回值
        Void joinAccept = completableFuture.thenAccept((v) -> {
            if (v.equals("11111")) System.out.println(v);
        }).join();
        System.out.println(joinAccept);
        // thenApply 依赖上个返回值 并返回计算结果 thenRun 不依赖上个返回值 无返回结果
        // thenAccept 消费类型 有参数无返回类型
        // thenApply a执行完执行b b依赖a返回值 有参数 有返回值
        // thenRun  a执行完执行b b不依赖a返回值 无参数 无返回值
        // thenRun 无返回值
        // 无返回值 join 结果 都为null 因为无结果
        Void joinRun = completableFuture.thenRun(() -> {
        }).join();
        System.out.println(joinRun);
    }

线程池 和 completableFuture 选择 及 三种情况

/**
* 线程池 和 CompletableFuture 选择
* @param args
*/
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(4);
CompletableFuture.supplyAsync(()->{
try {
TimeUnit.SECONDS.sleep(10);
System.out.println(Thread.currentThread().getName());
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return "1111";
},executorService).thenRun(()->{
try {
TimeUnit.SECONDS.sleep(10);
System.out.println(Thread.currentThread().getName());
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}).thenRun(()->{
try {
TimeUnit.SECONDS.sleep(10);
System.out.println(Thread.currentThread().getName());
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
});
executorService.shutdown();
}

/**
* 第一个没有传 线程池 则 从头开始使用 默认线程池
* 第一个注入线程池 则 使用注入线程池
* 第一个使用线程池 第二个使用 异步线程 则从二个开始使用 默认线程池
*
* 如果任务 处理时间过短 ,则会优化直接使用 main 主线程 不在使用声明线程
*/

 

CompletableFuture<String> playA = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            return "play a";
        });

        CompletableFuture<String> playB = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            return "play b";
        });

        // 两个线程比较 哪个跑的快 则返回快的 返回值  
        // 计算速度比较 方法
        CompletableFuture<String> applyToEither = playA.applyToEither(playB, f -> f + "is win");
        System.out.println(applyToEither.join());

 

long l = System.currentTimeMillis();
        CompletableFuture<Integer> a = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(6);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            return 10;
        });

        CompletableFuture<Integer> b = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(4);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            return 10;
        });
        // 整合两个异步线程结果 一个完成等另外一个,然后返回 整合结果
        CompletableFuture<Integer> result = a.thenCombine(b, Integer::sum);
        System.out.println(System.currentTimeMillis()-l);
        System.out.println(result.join());

CompletableFuture<Integer> result = CompletableFuture.supplyAsync(() -> {
return 10;
}).thenCombine(CompletableFuture.supplyAsync(() -> 20), Integer::sum)
.thenCombine(CompletableFuture.supplyAsync(() -> 30), Integer::sum);
System.out.println(result.join());
 

 

package org.example.config;

import java.util.concurrent.TimeUnit;

public class Person {

    public static void main(String[] args) {
        Iphone iphone = new Iphone();

        new Thread(Iphone::sentEmil).start();
        new Thread(iphone::hello).start();
    }
}

class  Iphone{


    /**
     *  普通方法加锁 成为对象锁
     *  静态方法加锁 成为类锁
     * 1.synchronized  修饰普通方法 则锁的是资源类的所有synchronized方法,第一个获取,其他需要等待
     * 2.synchronized 访问 两个实例对象或者访问非synchronized方法 则不会出现争抢资源问题,因为访问的不同资源
     * 3.static 静态synchronized 方法 则升级为class 模版锁,多少实例对象 都会指向同一个模版,一人获取其他等待 
     * 4.当调用两个种锁时(对象锁,类锁) 两者互补冲突 互不影响 
     *
     */
    public  static synchronized void sentEmil(){
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println("发邮件");
    }

    public synchronized void sentMs(){
        System.out.println("发短信");
    }

    public void hello(){
        System.out.println("hello");
    }

}

 

import java.util.concurrent.locks.ReentrantLock;

public class MyThreadDemo {
    public static void main(String[] args) {
        Ticket ticket = new Ticket();
        new Thread(()->{
            for (int i = 0; i < 100; i++) {
                ticket.sale();
            }
        }).start();
        new Thread(()->{
            for (int i = 0; i < 100; i++) {
                ticket.sale();
            }
        }).start();
        new Thread(()->{
            for (int i = 0; i < 100; i++) {
                ticket.sale();
            }
        }).start();

    }
}

class Ticket{
    private int num =50;

    // 默认 非公平锁  fair true 为公平锁
    ReentrantLock reentrantLock = new ReentrantLock(true);

    public void sale(){
        // 加锁
        reentrantLock.lock();
        if(num>0){
            System.out.println(Thread.currentThread().getName()+"卖出了第"+num--+"剩余"+num);
        }
        // 解锁
        reentrantLock.unlock();
    }

}

 

/** 两都为重入锁
     * synchronized 自动加锁 自动释放锁. 隐式锁
     * Lock (ReentrantLock)  手动加锁 手动释放 需要加锁释放需要一一对应。显式锁
     * 实现原理 每一个对象都一个锁计数器和一个持有该锁的线程指针
     * 每个锁对象拥有一个锁计数器和一个指向持有该锁的线程的指针。
     * 当执行monitorenter时,如果目标锁对象的计数器內零个 那么说明它没有被其他线程所持有,Java虚拟机会将该锁对象的持有线程设置为当前线程,并且将其计数器加1。
     * 在目标锁对象的计数器不为零的情况下,如果锁对象的持有线程是当前线程,那么Java 虚拟机可以将其计数器加1,否则需要等待,直至持有线程释放该锁。
     * 当执行monitorexit时,Java虚拟机则需将锁对象的计数器减1。计数器为零代表锁已被释放。
     * @param args
     */
    public static void main(String[] args) {
//        synchronized
       Lock lock = new  ReentrantLock();
        /**
         * 对象也作为锁 每个对象都会带有对象监视器 于monitor 关起来
         */
        Object o = new Object();
        synchronized (o){

        }

    }
/**
     * 死锁案例 a持有a 锁去获取b锁 b持有锁 去获取a锁 
     * (中间无等待时间因为线程过快,会导主线程main线程执行 自优化导致死锁失败)
     * @param args
     */
    public static void main(String[] args) {
        final Object objectA = new Object();
        final Object objectB = new Object();

        
        new Thread(()->{
            synchronized (objectA){
                System.out.println(Thread.currentThread().getName()+"持有a锁");
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                synchronized (objectB){
                    System.out.println(Thread.currentThread().getName()+"去获取b锁");
                }
            }
        }).start();

        new Thread(()->{
            synchronized (objectB){
                System.out.println(Thread.currentThread().getName()+"持有a锁");
                new Thread(()->{
                    synchronized (objectA){
                        System.out.println(Thread.currentThread().getName()+"持有a锁");
                        synchronized (objectB){
                            System.out.println(Thread.currentThread().getName()+"去获取b锁");
                        }
                    }
                }).start();
                synchronized (objectA){
                    System.out.println(Thread.currentThread().getName()+"去获取b锁");
                }
            }
        }).start();
    }
    /**
     * 死锁案例 a持有a 锁去获取b锁 b持有锁 去获取a锁
     * (中间无等待时间因为线程过快,会导主线程main线程执行 自优化导致死锁失败)
     * @param args
     */

    /**
     *
     * 检测程序死锁 有两种方式
     * 1. 终端输入jps -l 查看进程号 (jps = java ps -ef)
     * 2.jstack 进程号  查看堆栈信息
     *
     * 图形化工具 jconsole  本地链接 检查死锁 就可以显示死锁线程
     */
    public static void main(String[] args) {
        final Object objectA = new Object();
        final Object objectB = new Object();


        new Thread(()->{
            synchronized (objectA){
                System.out.println(Thread.currentThread().getName()+"持有a锁");
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                synchronized (objectB){
                    System.out.println(Thread.currentThread().getName()+"去获取b锁");
                }
            }
        }).start();

        new Thread(()->{
            synchronized (objectB){
                System.out.println(Thread.currentThread().getName()+"持有a锁");
                new Thread(()->{
                    synchronized (objectA){
                        System.out.println(Thread.currentThread().getName()+"持有a锁");
                        synchronized (objectB){
                            System.out.println(Thread.currentThread().getName()+"去获取b锁");
                        }
                    }
                }).start();
                synchronized (objectA){
                    System.out.println(Thread.currentThread().getName()+"去获取b锁");
                }
            }
        }).start();
    }

 

/**
     *  object 等待唤醒  注意 
     *  1.必须 所有线程方法 都被锁资源
     *  2.必须 先等待 后唤醒 否则 线程会一直 等待状态无法终止
     * @param args
     */
    public static void main(String[] args) {
        final Object objectA = new Object();

        Thread a = new Thread(() -> {
            synchronized (objectA){
                System.out.println(Thread.currentThread().getName()+"进来了。。。。。");
                try {
                    objectA.wait();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                System.out.println(Thread.currentThread().getName()+"结束了。。。。。");
            }
        },"a");
        a.start();
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        Thread b = new Thread(()->{
            synchronized (objectA){
                System.out.println(Thread.currentThread().getName()+"开始唤醒a线程");
                objectA.notify();
            }
        },"b");
        b.start();
    }
/**
     * 解决了 线程等待唤醒 操作需要被锁的问题
     *
     * 用于创建锁和其他同步类的基本线程阻塞原语。
     * 该类与使用它的每个线程关联一个许可证(在Semaphore类的意义上》。
     * 如果许可证可用,将立即返回park,并在此过程中消费;否则可能会阻止。
     * 如果尚未提供许可,则致电unpark获得许可。(
     * 与Semaphores不同,许可证不会累积。最多只有一个。〉
     * 可靠的使用需要使用volatile(或原子》变量来控制何时停放或取消停放。
     * 对于易失性变量访问保持对这些方法的调用的顺序,但不一定是非易失性变量访问。
     * 方法park和unpark提供了阻止和解除阻塞线程的有效方法,
     * 这些线程没有遇到导致不推荐使用的方法Thread.suspend和Thread.resume无法用于此类目的的问题:
     * 一个线程调用park和另一个线程尝试unpark将保留活跃性,由于许可证。
     * 此外,如果调用者的线程被中断,则会返回park,并且支持超时版本。
     * park方法也可以在任何其他时间返回,“无理由”,因此通常必须在返回时重新检查条件的循环内调用。
     * 在这个意义上,park可以作为“忙碌等待“的优化,不会浪费太多时间旋转,但必须与unpark配对才能生效。
     * 三种形式的park每个也支持blocker对象参数。
     * 在线程被阻基时记录此对象,以允许监视和诊断工具识别线程被阻止的原因。
     * 《此类工具可以使用方法getBlocker(Thread)访问阻止程序。
     * 强烈建议使用这些表单而不是没有此参数的原始表单。在锁实现中作为blocker提供的正常参数是this
     * @param args
     */
    public static void main(String[] args) {

        Thread thread = new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + "进来了....");
            LockSupport.park();
            System.out.println(Thread.currentThread().getName() + "被唤醒了....");

        });
        thread.start();
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        new Thread(()-> LockSupport.unpark(thread)).start();
    }

 

 
/**
     *   condition 等待唤醒  注意
     *  1.必须 所有线程方法 都被锁资源
     *  2.必须 先等待 后唤醒 否则 线程会一直 等待状态无法终止
     * @param args
     */
    public static void main(String[] args) {
        ReentrantLock lock = new ReentrantLock();
        Condition condition = lock.newCondition();

        new Thread(()->{
            lock.lock();
            System.out.println(Thread.currentThread().getName()+"进来了........");
            try {
                condition.await();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }

            System.out.println(Thread.currentThread().getName()+"被唤醒了......");
            lock.unlock();
        }).start();
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        new Thread(()->{
            lock.lock();
            condition.signal();
            lock.unlock();
        }).start();
    }

 

public static void main(String[] args) {

        /**
         * 具体来说,当对一个线程,调用 interrupt()时:
         * ① 如果线程处于正常活动状态,那么会将该线程的中断标志设置为true,仅此而已。
         * 被设置中断标志的线程将继续正常运行,不受影啊。
         * 所以,interrupt()并不能真正的中断线程,需要被调用的线程自己进行配合才行
         * ② 如果线程处于被阻塞状态(例如处于sleep, wait, join 等状态),
         * 在别的线程中调用当前线程对象的interrupt方法,那么线程将立即退出被阻塞状态,
         * 并抛出一个InterruptedException异常。
         interrupt()方法是一个实例方法它通知目标线程中断,也仅是设置目标线程的中断标志位为true。
         */
Thread t1 = new Thread(() -> {
for (int i = 0; i < 30; i++) {
if (Thread.currentThread().isInterrupted()) {
System.out.println(Thread.currentThread().getName() + ":中断");
break;
}
try {
TimeUnit.MILLISECONDS.sleep(200);
} catch (InterruptedException e) {
//重新中断线程
Thread.currentThread().interrupt();
e.printStackTrace();
}
System.out.println("===interrupt=== : " + i);
}
}, "t1");
t1.start();
try {
TimeUnit.MILLISECONDS.sleep(2000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
t1.interrupt();

Thread thread = new Thread(() -> { }); thread.interrupt(); /** islnterrupted()方法也是一个实例方法它判断当前线程是否被中断(通过检查中断标志位)并获取中断标志 */ boolean interrupted1 = thread.isInterrupted(); /** Thread类的静态方法interrupted() 返回当前线程的中断状态真实值(boolean类型)后会将当前线程的中断状态设为false,此方法调用之后会清除当前线程的中断标志位的状态( 将中断标志置为false了),返回当前值并清零置false */ Thread.interrupted(); }

 

static volatile boolean flag = false;

    public static void main(String[] args) throws InterruptedException {
        new Thread(() -> {
            while (true) {
                if (flag) {
                    System.out.println(Thread.currentThread().getName() + "掐灭烟头");
                    break;
                }
                System.out.println(Thread.currentThread().getName() + "正在吸烟。。。");
            }
        },"t1").start();

        TimeUnit.MILLISECONDS.sleep(20);

        new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + "  禁止吸烟!!");
            flag = true;
        },"t2").start();
    }
tatic AtomicBoolean flag = new AtomicBoolean(false);

    public static void main(String[] args) throws InterruptedException {
        new Thread(() -> {
            while (true) {
                if (flag.get()) {
                    System.out.println(Thread.currentThread().getName() + "掐灭烟头");
                    break;
                }
                System.out.println(Thread.currentThread().getName() + "正在吸烟。。。");
            }
        },"t1").start();

        TimeUnit.MILLISECONDS.sleep(20);

        new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + "  禁止吸烟!!");
            flag.set(true);
        },"t2").start();
    }

 

package org.example.config;

public class Person {

    /**
     * 双端检锁
     *  当多线程的 jvm优化 重新排序 造成提前释放锁 其他线程进来拿到null  造成空指针
     *  加volatile 禁排序 避免空指针
     */
    private  volatile static Person person;

    private Person(){}
    public static Person getPerson() {
        if (person == null) {
            synchronized (Person.class) {
                person = new Person();
            }
        }
        return person;
    }
}

 

package com.chen.MyJuc.service.impl;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

public class PersonServiceImpl {

    static volatile boolean i = true;
    static CountDownLatch countDownLatch = new CountDownLatch(1);
    public static void main(String[] args) throws InterruptedException {
        new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + "come in");
            while (i) {

            }
        }, "a").start();
        TimeUnit.SECONDS.sleep(1);
        new Thread(() -> {
            i = false;
        }, "b").start();
    }
}

 

package org.example.service;

import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

class House{
    int num;

    ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(()->0);

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

public class PersonService {

    /**
     *  ThreadLocal  底层是 ThreadLocalMap 创建实例的时候把实例以key 值以value 粗村
     *  ThreadLocalMap 继承若引用 防止内存oom 内存溢出
     *  在多线程的尤其线程池的情况 必须副本回收 防止线程复用 造成逻辑混乱 
     * @param args
     * @throws InterruptedException
     */
    public static void main(String[] args) throws InterruptedException {
        House house = new House();
        ExecutorService executorService = Executors.newFixedThreadPool(6);
        CountDownLatch countDownLatch = new CountDownLatch(20);
        for (int i = 0; i < 20; i++) {
            executorService.submit(()->{
                try {
                    Random random = new Random();
                    int j = random.nextInt(10);
                    house.add();
                    System.out.println(house.threadLocal.get());
                } finally {
                    house.threadLocal.remove();
                }
                countDownLatch.countDown();
            });
        }
        countDownLatch.await();
        executorService.shutdown();
        System.out.println("--------------------");
        System.out.println(house.threadLocal.get());
    }
}
package org.example.service;

import java.util.concurrent.TimeUnit;

class House{
    String name;

    Integer age;

    @Override
    protected void finalize() throws Throwable {
        System.out.println("回收后");
    }
}

public class PersonService {

    /**
     *  new 为强引用 在内存gvm 满的时候 不会被强行回收
     *  当空指针的时候会被触发回收,回收前触发的方法
     * @param args
     * @throws InterruptedException
     */
    public static void main(String[] args) throws InterruptedException {
        House house = new House();
        System.out.println(house);
        house=null;
        System.gc();
        TimeUnit.SECONDS.sleep(2);
        System.out.println(house);
    }
}
/**
     * 软引用 内存满一定回收  不满 不回收
     * @param args
     * @throws InterruptedException
     */
    public static void main(String[] args) throws InterruptedException {
        SoftReference<House> softReference = new SoftReference<>(new House());
        System.gc();
        TimeUnit.SECONDS.sleep(2);
        System.out.println(softReference.get());
        for (int i = 0; i < 10000000; i++) {
            byte[] d = new byte[11098888*19];
        }
        System.out.println(softReference.get());
    }

/**
* 弱引用 不管内存满不满 gc 运行都会回收
* 软 弱引用 通常 在内存缓存大量数据 内存不足时 自动优化使用
* @param args
* @throws InterruptedException
*/
public static void main(String[] args) throws InterruptedException {
WeakReference<House> weakReference = new WeakReference<>(new House());
System.out.println(weakReference.get());
System.gc();
TimeUnit.SECONDS.sleep(1);
System.out.println(weakReference.get());
}
 

 

posted @ 2023-11-27 16:09  chen1777  阅读(19)  评论(0)    收藏  举报