在通过例子分析线程安全之前先 看了解这些 知识
在去看例子会清晰一点
Java有三大变量 静态变量:在方法区。 实例变量:在堆当中 局部变量:在栈中。 以上三大变量中: 局部变量永远都不会存在线程安全问题。 因为局部变量不共享。(一个线程一个栈。) 局部变量在栈中。所以局部变量永远都不会共享。 实例变量在堆中,堆只有1个。 静态变量在方法区中,方法区只有1个. 堆和方法区都是多线程共享的,所以可能存在线程安全问题。 局部变量+常量:不会有线程安全问题。 成员变量:可能会有线程安全问题。 【成员变量包括实例变量(存储在堆内存)和静态变量(存储在方法区内存)】 局部变量存储在栈内存当中,栈不共享,不会有线程安全的问题
常见线程安全类
String Integer Random Vector Hashtable java.util.concurrent 包下的类 ArrayList是非线程安全的。vector是线程安全的。 HashMap Hashset是非线程安全的。Hashtable是线程安全的。 如果使用局部变量的话: 建议使用: stringBuilder. 因为局部变量不存在线程安全问题。 选择stringBuilder.stringBuffer效率比较低。
总结: 实现线程安全有三种方式:1.无共享变量2.共享变量不可变3.同步
下面请跟我分析一下代码是否存在线程安全的问题,全部看完相信会有很大帮助
例一:
public class MyServlet extends HttpServlet {
// 是否安全?
Map map = new HashMap<>(); //不安全 因为HashMap当中没有synchronized修饰 是非安全的
// 是否安全?
String S1 = "..."; //安全 因为String的不可变类 属于共享变量不可变
// 是否安全?
final String S2 = "..."; //安全的 本身String就是线程安全的 加上final就更是了
// 是否安全?
Date D1 = new Date(); //不安全 日期类不属于线程安全的
// 是否安全?
final Date D2 = new Date(); //不安全 虽然final Date D2 的 final修饰的
//但是他new Date(); 里面 的年月日会变 总结 日期是可变类 而字符串是不可变的
}
例二
public class MyServlet extends HttpServlet {
// 是否安全?
private UserService userService = new UserServiceImpl();
public void doGet(HttpServletRequest request, HttpServletResponse response) {
userService.update(...);
}
}
public class UserServiceImpl implements UserService {
// 记录调用次数
private int count = 0;
public void update() {
// ...
count++;
}
}
例三
spring IOC
@Aspect
@Component
public class MyAspect {
// 是否安全?
private long start = 0L;
@Before("execution(* *(..))") //前置通知
public void before() {
start = System.nanoTime(); //记录开始时间
}
@After("execution(* *(..))") //后置通知
public void after() {
long end = System.nanoTime(); //记录结束时间
System.out.println("cost time:" + (end-start)); //计算耗时 通过切面的功能,把耗时功能给抽离出来
}
}
例四
//MVC的三层调用
public class MyServlet extends HttpServlet {
// 是否安全
private UserService userService = new UserServiceImpl();
public void doGet(HttpServletRequest request, HttpServletResponse response) {
userService.update(...);
}
}
public class UserServiceImpl implements UserService {
// 是否安全
private UserDao userDao = new UserDaoImpl();
public void update() {
userDao.update();
}
}
public class UserDaoImpl implements UserDao {
public void update() {
String sql = "update user set password = ? where username = ?";
// 是否安全
try (Connection conn = DriverManager.getConnection("","","")){
// ...
} catch (Exception e) {
// ...
}
}
}
例五
public class MyServlet extends HttpServlet {
// 是否安全
private UserService userService = new UserServiceImpl();
public void doGet(HttpServletRequest request, HttpServletResponse response) {
userService.update(...);
}
}
public class UserServiceImpl implements UserService {
// 是否安全
private UserDao userDao = new UserDaoImpl();
public void update() {
userDao.update();
}
}
public class UserDaoImpl implements UserDao {
// 是否安全
private Connection conn = null;
public void update() throws SQLException {
String sql = "update user set password = ? where username = ?";
conn = DriverManager.getConnection("","","");
// ...
conn.close();
}
}
例七
public abstract class Test {
public void bar() {
// 是否安全
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
foo(sdf);
}
public abstract foo(SimpleDateFormat sdf);
public static void main(String[] args) {
new Test().bar();
}
}
//其中 foo 的行为是不确定的,可能导致不安全的发生,被称之为外星方法
public void foo(SimpleDateFormat sdf) {
String dateStr = "1999-10-11 00:00:00";
for (int i = 0; i < 20; i++) {
new Thread(() -> {
try {
sdf.parse(dateStr);
} catch (ParseException e) {
e.printStackTrace();
}
}).start();
}
}
看完相信你一定有所收获,一起加油!



