Java牛客刷题笔记
线程安全问题
java中的线程安全是什么:
就是线程同步的意思,就是当一个程序对一个线程安全的方法或者语句进行访问的时候,其他的不能再对他进行操作了,必须等到这次访问结束以后才能对这个线程安全的方法进行访问
什么叫线程安全:
如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。
或者说:一个类或者程序所提供的接口对于线程来说是原子操作或者多个线程之间的切换不会导致该接口的执行结果存在二义性,也就是说我们不用考虑同步的问题。
线程安全问题都是由全局变量及静态变量引起的。
若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作,一般都需要考虑线程同步,否则就可能影响线程安全。
看过vector源码的同学就会知道他的许多操作都是加了synchronized修饰的比如他的添加元素。(不知道synchronized是什么意思的自行百度!)
public synchronized void addElement(E obj) { modCount++;
ensureCapacityHelper(elementCount + 1); elementData[elementCount++] = obj;
}
而HashMap的所有操作都没有加synchronized修饰 ,不如他的put源码
1 | public V put(K key, V value) { |
由此就可以判断出谁是线程安全的了。
不可变类(Immutable class)
不可变类(Immutable class)是指当一个对象被创建出来以后,它的值就不能被修改了,也就是说,一个对象一旦被创建出来,在其整个生命周期中,它的成员变量就不能被修改了。它有点类似于常量(const),只允许别的程序读,而不允许别的程序进行修改。
在Java类库中,所有基本类型的包装类都是不可变类,例如Integer、Float等。此外,String也是不可变类。可能有人会有疑问,既然 String 是不可变类,那么为什么还可以写出如下代码来修改String类型的值呢?
1 | public class Test |
1
2
3
4
5
6
7
程序的运行结果为:
Hello world
表面上看,好像是修改String类型对象s的值。其实不是,Strings=“Hello”语句声明了一个可以指向String类型对象的引用,这个引用的名字为s,它指向了一个字符串常量“Hello”。s+=” world”并没有改变s所指向的对象(由于“Hello”是String类型的对象,而String又是不可变量),这句代码运行后,s指向了另外一个String类型的对象,该对象的内容为“Hello world”。原来的那个字符串常量“Hello”还存在与内存中,并没有被改变。
原则
1)类中所有的成员变量被private所修饰。
2)类中没有写或者修改成员变量的方法,例如:setxxx。只提供构造函数,一次生成,永不改变。
3)确保类中所有的方法不会被子类覆盖,可以通过把类定义为 final 或者把类中的方法定义为final来达到这个目的。
4)如果一个类成员不是不可变量,那么在成员初始化或者使用get方法获取该成员变量是需要通过clone方法,来确保类的不可变性。
5)如果有必要,可以通过覆盖 Object 类的 equals()方法和hashCode()方法。在 equals()方法中,根据对象的属性值来比较两个对象是否相等,并且保证用 equals()方法判断为相等的两个对象的hashCode()方法的返回值也相等,这可以保证这些对象能正确地放到HashMap或HashSet集合中。
优缺点
优点
在Java语言中,之所以设计有很多不可变类,主要是因为不可变类具有使用简单、线程安全、节省内存等优点
缺点
例如,不可变的对象会因为值的不同而产生新的对象,从而导致无法预料的问题,所以,切不可滥用这种模式。
对于一些敏感的数据(例如密码),为什么使用字符数组存储比使用String更安全?
答案:在Java语言中,String是不可变类,它被存储在常量字符串池中,从而实现了字符串的共享,减少了内存的开支。正因为如此,一旦一个String 类型的字符串被创建出来,这个字符串就会存在于常量池中,直到被垃圾回收器回收为止。
因此,即使这个字符串(比如密码)不再被使用,它仍然会在内存中存在一段时间(只有垃圾回收器才会回收这块内容,程序员没有办法直接回收字符串)。此时有权限访问memory dump(存储器转储)的程序都可能会访问到这个字符串,从而把敏感的数据暴露出去,这是一个非常大的安全隐患。
如果使用字符数组,那么一旦程序不再使用这个数据,程序员就可以把字符数组的内容设置为空,此时这个数据在内存中就不存在了。从以上分析可以看出,与使用 String 相比,使用字符数组,程序员对数据的生命周期有更好的控制,从而可以增强安全性。
原文链接:https://blog.csdn.net/david2000999/article/details/121450905