多线程:对象的发布(publish)、逸出(escape),逸出解决方案

对象发布(publish)

含义:一个对象可以在当前作用域之外的代码中使用。

发布方式:如懒汉式、饿汉式、工厂模式等发布的对象。

 

代码示例:

package com.bicai.publish;

import java.util.ArrayList;
import java.util.List;

/**
 * @Author lizhengjun
 * @Date 2020/6/24
 * @Desc 发布水果对象(懒汉式)
 */

public class PublishFruit {

    private List<String> fruitList = null;

    /**
     * @description: 发布水果集合对象(注:线程不安全)
     * @return: 水果集合对象
     * @date: 2020/6/24 15:33
     */
    public List<String> getInstance() {
        if(fruitList == null) {
            // 对象数据初始化
            fruitList = new ArrayList<>();
            fruitList.add("apple");
            fruitList.add("orange");
        }
        return fruitList;
    }
}

 

测试:

    public static void main(String[] args) {
        PublishFruit publishFruit = new PublishFruit();
        // 获取水果集合对象
        List<String> fruitList = publishFruit.getInstance();
        System.out.println("水果集合对象:" + fruitList);
    }

 

输出结果:

水果集合对象:[apple, orange]

 

对象逸出(escape)

含义:发布对象内部状态可能会破坏封装性,并使得程序难以维持不变性条件;当某个不应该发布的对象被发布时,这种情况就称为逸出。

 

代码示例:

package com.bicai.publish;

/**
 * @Author lizhengjun
 * @Date 2020/6/24
 * @Desc 对象逸出演示
 */

public class EscapeThread {

    private String taskNumber = "N001";     // 任务编号
    private String taskName = null;    // 任务名称

    public EscapeThread() {
        new Thread(new EatFruitTask()).start();
        new Thread(new EatFruitTask()).start();
        // 初始化任务名称
        taskName = "吃水果";
    }

    private class EatFruitTask implements Runnable {
        @Override
        public void run() {
            String user = Thread.currentThread().getId() + "---" + Thread.currentThread().getName();
            System.out.println(user + ":吃水果...开始");
            System.out.println("任务编号taskNumber:" + taskNumber + ",任务名称taskName:" + taskName);
            System.out.println(user + ":吃水果...结束");
        }
    }
}

 

测试:

    public static void main(String[] args) {
        EscapeThread escapeThread = new EscapeThread();
    }

 

输出结果:

12---Thread-0:吃水果...开始
13---Thread-1:吃水果...开始
任务编号taskNumber:N001,任务名称taskName:null
任务编号taskNumber:N001,任务名称taskName:吃水果
13---Thread-1:吃水果...结束
12---Thread-0:吃水果...结束

 

对象逸出解决方案

代码示例:

/**
 * @Author lizhengjun
 * @Date 2020/6/24
 * @Desc 对象逸出解决方案
 */

public class EscapeThreadSolution {

    private String taskNumber = "N001";     // 任务编号
    private String taskName = null;    // 任务名称

    Thread thread1 = null;
    Thread thread2 = null;

    public EscapeThreadSolution() {
        thread1 = new Thread(new EatFruitTask());
        thread2 = new Thread(new EatFruitTask());
        // 初始化任务名称
        taskName = "吃水果";
    }

    public void startTask() {
        thread1.start();
        thread2.start();;
    }

    private class EatFruitTask implements Runnable {
        @Override
        public void run() {
            String user = Thread.currentThread().getId() + "---" + Thread.currentThread().getName();
            System.out.println(user + ":吃水果...开始");
            System.out.println("任务编号taskNumber:" + taskNumber + ",任务名称taskName:" + taskName);
            System.out.println(user + ":吃水果...结束");
        }
    }
}

 

测试:

    public static void main(String[] args) {
        EscapeThreadSolution escapeThreadSolution = new EscapeThreadSolution();
        escapeThreadSolution.startTask();
    }

 

输出结果:

13---Thread-1:吃水果...开始
12---Thread-0:吃水果...开始
任务编号taskNumber:N001,任务名称taskName:吃水果
12---Thread-0:吃水果...结束
任务编号taskNumber:N001,任务名称taskName:吃水果
13---Thread-1:吃水果...结束

 

解决思路:避免在构造函数里启动线程;

 

温馨提示

导致对象逸出的情况会有很多,如系统资源初始化、上下文初始化等,针对不同情况采用不同的解决方式。

 

posted @ 2020-06-24 16:18  浅唱蛋蛋  阅读(371)  评论(0)    收藏  举报