00:00
由于是单例多线程的,它是运行在单例多线程这种环境下的,所以它的运行可能存在。线程安全问题。那么什么是线程安全问题?所以下边啊,我们。要说一些理论知识了。先来看一下县城安全。那么同时满足以下两个条件,那么它就有可能会出现线程安全问题,你注意是同时满足啊哪两个条件,一个存在多线程并发访问。另外一个存在可修改的共享数据,这两个条件缺一不可。那么当多个线程同时修改同一个。
01:00
共享数据的时候。你改这个数据,我也改这个数据,那么后修改的数据会将先修改的数据给覆盖掉。对数据先进行修改的用户,读取到的不是自己改的数据。那么这种情况就是线程安全问题,你比如说比如说我这儿。把这个年龄age我修改了,给它改成23了。我给他改成23了,紧接着你又给他改了,你给他改成25了,那我认为我改的时候给他改成23了,那我读吧,一读这个age发现是25,那不对呀,我改了23怎么成了25了。这就是线程安全问题,所以这里边啊,线程安全问题出现的两个条件,多线程并发访问。
02:03
然后就是。可修改的共享数据。那好,关于线程并发啊,这关于这个线程安全问题呢,我们现在对虚拟机里边啊,可能存在现身安全的问题呢,这个数据我们进行一下分析。那我们虚拟机里边啊,我对于我们程序员来说能够用到的内存区域。其实就三个占,内存堆、内存和方法区。那么我们就来分析这三个。这三个啊,先来说这。战战是什么了呀?里面放什么呀?战里边放的是方法战争呐,战里边放的是方法,战争一个方法是不是在这个战里边会以一个战争的形式出现呢?
03:10
那么占内存你需要注意啊。它是多立的,这儿说了它是多立的。什么叫多利的?就是我们的虚拟机会为每一个线程创建一个站。那所以。所以这个数据不是共享的,也就是说你来访问的时候,虚拟机会给你创建一个。占内存,我来访问的时候会给我创建一个占内存,那么我调用方法的时候会把这个方法。给他形成一个战争,然后压阵进到我的战里边,那你的战里边没有,你调了另外一个方法,他会将。你调呢,另外一个方法给他形成一个战争,压到你的那个站里边。
04:01
所以所以它里边数据是不存在线程安全问题的,谁访问谁的是吧,根本就不交叉。所以啊,所以。所以所以什么了,所以你注意我们方法里边的局部变量是出现在哪儿呢?是出现在方法战争里边的。所以方法中的局部变量是不存在线程安全问题的。这是你要注意的啊。占内存中的数据是不存在,确切的说占内存中的方法占帧,或者说再说的简单一些啊,就是方法里边的局部变量是不存在线程安全问题的。That three。堆内存不一样。
05:00
一个虚拟机只有一个对内存。坏了,这堆看来是共享的呀,堆内存是共享的,那么堆里边放了什么东西啊?啊,堆里边是放什么的。堆里边放的是两样东西啊,一个是我们拗出来的对象。一个是庶族。这两样东西是放在堆里边的。那么它放在堆里边,也就意味着我们多线程对于堆里边对象的访问。它是共享的。对堆中的对象是共享的。当然我们知道啊,你没一个对象在堆内存里面放的什么东西。你说堆那边出出现的是什么,实际上就是这个对象的成员变量的值啊。
06:02
对不对。我了个student,这个student里边有name age。那么这个堆内存里边放的什么?就是name?这三个成员变量,它占有的。他的数据在里边放着,当然了,除了这些数据以外,还有还有其他的数据啊,比如说。他的父人。是吧,它的父类的那个无参构造器,创建那个对象,还有谁,还有object。那个创建那个对象,当然我们关心的是谁,我们关心的就是它的成员变量,所以所以啊,我们说我们实际创建的对象啊。它就是成员变量的值的一个集合。那堆内存中的数据存在线程安全问题,为什么共享的?
07:01
它是共享的。OK啊,这是。堆内存啊,再看方法区,方法区里边放的什么东西。方法区里边放的什么。方法器里边其实放的,那我们关心的东西是什么?是静态变量和常量。静态变量和常量是存放在方法区的,当然了,除了静态变量和常量以外,还有什么东西?还有?这个这个这个这个什么,呃,我们方法的。代码片段也存放在方法区,什么叫方法的代码片段呢?这个站里面放在什么?放的是方法战争是吧?方法战争是什么?实际上方法战争里边有什么东西,它有的是方法的签名。
08:10
知道方法签名吧,对不对,就是方法头啊,方法头的信息在方法战争里边,然后方法里边的局部变量在方法战争里边。当然还有一些。方法调用它的返回地址啊什么的,还有这些信息放在方法战争,而我们真正方法里边执行的那个代码没在战争里边放着啊,在哪儿呢?它是在方法区呢,只不过这个东西我们不关心,我们关心的是。静态变量和常量。常量有常量池啊。对不对,它有常量池,常量池是方法区里边的一块内存。一个虚拟机只存在一个方法区,所以这一听这个东西就知道它是共享的。
09:00
方法区是多线程共享的,但是你注意。它是共享的,是不错常量,什么叫常量,它的值不能改变的量是不是就是常量啊,常量是不能被修改的,好看这这。存在线程安全问题的两个条件,一个是多线程并发访问。就共享的是吧,那共享他占。方法区里边的常量占着共享的,但。他不可修改,它是敞量啊,不可修改,所以所以它不存在线程安全问题。所以我们方法区中的常量是不存在线程安全问题的,但静态变量你注意,静态变量是多线程共享的。既然是静态变量,这个值是可以修改的,所以静态变量存在线程安全问题。
10:07
关于内存情况啊,虚拟机的内存情况,如果你不是很清楚的话,你可以参考由瑞就是我主编的由清华大学出版社出版的Java基础,Java零基础教程。那那个里边比较详细的介绍了内存的情况啊好,那么。县城安全问题啊,那么怎么解决?当然啦,那现场安全就一定不好吗?那不是?那也不是啊,这是线程,实际上线程安全问题是指的什么?是线程它不安全了啊,这个安全问题是指的它线程不安全了,那这个线程不安全就一定不好吗?也不是我们一会儿会说对线程,你看这儿要要讲对线程安全问题的合理利用,我们可以利用它。
11:04
但是整体上来说,我们不想让它出现这种线程不安全这种问题,所以我们如何解决呢?解决的思路看着下面是解决的思路,第一。对于一般性的累。不要定义成单立的。不要定义成单立的。如果说你没有特殊要求,就不要定义成单列,因为你定义成单立的,单立的就是什么,它就有可能会被共享啊。对不对?除非你项目里边有特殊的需求,或者这个对象属于什么重量级对象,你注意是重量级对象。什么叫重量级对象?就是创建这个对象需要占用较大的系统资源,就是重量级对象。回头大家听啊,学习我后边,呃,对于框架专题讲解的时候,我们会了解到框架里边有很多重量级的对象,那这些重量级的对象它就是单立的。
12:15
好。这是第一个啊,就是我们尽量不要定义成单立的。然后呢,无论是否为单立类,尽量不使用静态变量,因为你一旦你用了静态变量,静态变量在哪,是不是方法区啊,在方法区,它就方法区里边数据存在线程安全问题啊。刚刚说过的是不是,所以我们尽量不要使用静态变量。如果,那必须要定义成单立的。那么单例类里边尽量不使用成员变量,单立类里边尽量不使用成员变量。
13:04
大家想一下我们的是什么?是不是单例多线程的呀?所以刚才我们说了,它是单利的,单利多线程的,所以它存在线程安全问题,所以我们色里在使用的时候尽量不要往里边放可修改的全员命令。你注意啊,不是不能放成员变量,而是尽量不要放可修改的成员变量。你比如说我们在在前面学习的时候啊,我们其实还真是往里边定义成员变量了哪个东西。Somebody can't f?So config。我们在哪?在这儿,Subject con?你看这是不是成为啊。
14:02
这是成员变量,呃,这个这是成员变量,是这个里边成员变量,那么它一旦声明了成员变量,它是不是就存在线程安全问题呢?是不是?不是啊,你不要这样一写,你说诶这不就现存在现在安全问题啊,这个不是为什么,它是不可修改的。怎么就不可修改了,程序员是不可修改它的。他的知从哪儿来的?是他开的服务器给我们传进来的,你不管谁用,对于它的配置,配置信息都是一模一样的,所以它不存在,就是程序员无法修改它,因为我们根本就没有提供你,你看到这里边有没有一个方法叫set。Some con guy。是没有啊,他只有get,没有set。没有赛德,这说明什么?这个成员变量是不可修改的,所以它不存在线程安全问题。
15:07
好。如果说单类类类里边啊,你是单例,而且是多线程的,但还真必须要。要使用到可修改的成员命令。那么我们可以。对这个成员变量的操作添加串行化索。Synchronized。这个大家知道吧。是不是这个Java基础的时候,我们说过这是实现什么线程同步。什么叫线程同步,就是我在修改这个,我在操作这个变量的时候,你也来操作了,对不起,我给它加着锁呢。你不能改。你不能操作它,你得等我操作完了,我把这个锁让出来了,你才能改。
16:02
他得一个一个挨着来。这是串行化的,它是串型化synchron吗?他不是并行的,不是同时做,而是一个一个挨着来做。那我们大家知道,你一旦代码改成了串行化了。那你程序的执行效率是不是就。降低了很多呀。所以。最好不要使用。这种同步机制。不要使用它,你用了它,你的代码执行效率会很低。所以我们啊,这说的线程安全问题,它的解决方案这个啊,我们大家啊,就是了解一下什么是线程安全。哪儿的数据存在有线程安全问题,以及我们解决线程安全问题的它的思路是什么?了解一下就OK了,这是纯理论的东西啊,我们一会儿写代码让大家体会一下。
我来说两句