线程安全(java)
引言:一为T1,T2线程想要调用Dept中的name属性发生的线程安全问题
二、可变字符串举例
请求过多会造成内存溢出,如代码
栈内存溢出:每一个线程对应着一个栈,栈会分配内存,此时如果请求过多,这时候内存不够了,就会发生栈内存溢出。
栈溢出是指不断的调用方法,不断的压栈,最终超出了栈允许的栈深度,就会发生栈溢出,比如递归操作没有终止,死循环
public class TestString1 {
public static void main(String[] args) throws Exception {
//二、可变字符串举例
//可变字符串
//StringBuffer(线程安全),StringBuilder
//new:一个线程进来就创建一次
//具体使用Stringbuffer还是StringBuilder还是要看使用场景
//由于目前使用的是多例模式,所以使用StringBuilder不影响线程安全
StringBuilder buff = new StringBuilder();
String s = "";
for (int i = 0; i < 100000000000L; i ++ ){
// s = s + i;
buff.append(i);
}
System.out.println("s = " + buff);
//一、引入
//所谓的线程安全问题,其实是多线程并发执行时,对共享内存中的共享对象的属性进行修改时
//所导致的数据冲突问题
//分析错误原因
//多线程:单线程
//共享内存:多线程共享的内存:堆内存,方法区内存
// :将对象放置在独享内存中(栈上分配,逃逸分析)
//共享对象:多线程访问的是同一个对象:Servlet
// : 多例,每一个线程使用一个对象:Struts2
//属性:对象属性只有一个,方法没事(需要压栈,调用一次压栈一次,不影响)
//修改:多线程同时修改
Dept2 dept = new Dept();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
dept.name = "开发部";
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(dept.name);
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
dept.name = "执行部";
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(dept.name);
}
});
t2.start();
t1.start();
System.out.println("main方法执行完毕");
//main方法执行完毕
}
}
class Dept{
public String name = "1111";
}
下图为线程不安全的:多个线程同时调用name属性
下图为线程安全的