线程安全第三大类问题——对象发布和初始化的安全问题

线程安全第三大类问题——对象发布和初始化的安全问题

什么是发布

  • 什么是发布:将对象可以超过这个类范围之外可以使用;比如对象声明为public,或者方法的return是一个对象,或者将类作为参数传到其他类的方法中,这些都能称之为发布。

什么是逸出

  • 什么是逸出:发布到了不该发布的地方就叫逸出。
  1. 方法返回一个private对象(private本意是不让外部访问)
  2. 还未完成初始化(构造函数没完全执行完毕)就把对象提供给外界。比如:
    • 在构造函数中未初始化完毕就this赋值
    • 隐式逸出——注册监听事件
    • 构造函数中运行线程

对于逸出的第一条,可以返回副本。

* 代码演示

在构造函数中未初始化完毕就this赋值

package controller;

/**
 * 在构造函数中未初始化完毕就this赋值
 */
public class MultiThradsError4 {
    static Point point;

    public static void main(String[] args) throws InterruptedException {
        new PointMaker().start();
        //两种执行结果不同,可以自己执行一下
//        Thread.sleep(10);
        Thread.sleep(105);
        if(point != null){
            System.out.println(point);
        }
    }
}

class Point{
    private final int x,y;

    public Point(int x, int y) throws InterruptedException {
        this.x = x;
        MultiThradsError4.point = this;
        Thread.sleep(100);
        this.y = y;
    }

    @Override
    public String toString() {
        return "Point{" +
                "x=" + x +
                ", y=" + y +
                '}';
    }
}

class PointMaker extends Thread{
    @Override
    public void run(){
        try {
            new Point(1,1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

隐式逸出——注册监听事件(使用观察者模式)

package controller;

import java.awt.*;
import java.util.EventListener;

/**
 * 隐式逸出——注册监听事件(使用观察者模式)
 */
public class MultiThreadError5 {

    int cout;

    public MultiThreadError5(MySource source) {
  		//注册监听器
        source.registerListener(new EventListener() {
            @Override
            public void onEvent(Event e) {
                System.out.println("\n我得到的数字"+cout);
            }
        });

        for (int i =0; i<10000;i++){
            System.out.print(i);
        }
        cout = 100;
    }

    public static void main(String[] args) {
        MySource mySource = new MySource();
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                mySource.eventCome(new Event() {
                });
            }
        }).start();
        MultiThreadError5 multiThreadError5 = new MultiThreadError5(mySource);
    }

    static class MySource{
        private EventListener listener;

        void registerListener(EventListener eventListener){
            this.listener = eventListener;
        }

        void eventCome(Event e){
            if(listener != null){
                listener.onEvent(e);
            }else{
                System.out.println("还未初始化完毕");
            }
        }
    }

    interface EventListener{
        void onEvent(Event e);
    }

    interface Event{
    }
}

构造函数中新建线程

package controller;

import java.util.HashMap;
import java.util.Map;

/**
 * 构造函数中新建线程
 */
public class MultiThreadError6 {
    private Map<String,String> states;

    public MultiThreadError6() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                states = new HashMap<>();
                states.put("1","周一");
                states.put("2","周二");
                states.put("3","周三");
                states.put("4","周四");
            }
        }).start();

    }

    public Map<String,String> getStates(){
        return states;
    }

    public static void main(String[] args) throws InterruptedException {
        MultiThreadError6 multiThreadError6 = new MultiThreadError6();
        //延迟一下结果不同
//        Thread.sleep(1000);
        System.out.println(multiThreadError6.states.get("1"));
    }
}

上篇:线程安全第二大类问题——死锁
下篇:多线程带来的性能问题

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值