JUC学习笔记——共享模型之管程( 五 )

  • 但注意它们多个方法的组合不是原子的!
  • 我们采用代码进行简单解释:
    /*下述的单个方法都是原子且安全性的*/ Hashtable table = new Hashtable();new Thread(()->{table.put("key", "value1");}).start();new Thread(()->{table.put("key", "value2");}).start();/*但当这些方法组合起来,就无法保证其线程安全性*/ Hashtable table = new Hashtable();// 线程1,线程2都执行时,可能出现下述情况// 线程1get==null,线程2get==null,线程2put,线程1put;导致线程安全性错误出现if( table.get("key") == null) { table.put("key", value);}常见题型分析我们直接给出代码来进行题型分析:
    /*题目1*/// MyServlet是Servlet类,应用于Tomcat的多线程上public class MyServlet extends HttpServlet {// 是否安全?不是,不属于线程安全类Map<String,Object> map = new HashMap<>();// 是否安全?是,属于不变类型String S1 = "...";// 是否安全?是,属于不变类型final String S2 = "...";// 是否安全?不是,不属于线程安全类Date D1 = new Date();// 是否安全?是,属于不变类型final Date D2 = new Date();public void doGet(HttpServletRequest request, HttpServletResponse response) {// 使用上述变量}}/*题目2*/public class MyServlet extends HttpServlet {// 是否安全?不是,底层使用Impl,里面包含了count这个共享数据,且没有使用锁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++;}}/*题目3*/// 这里是Spring的@Aspect,属于单例,也是共享@Aspect@Componentpublic class MyAspect {// 是否安全? 不是,start属于共享数据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));}}/*题目4*/public class MyServlet extends HttpServlet {// 是否安全 是,调用Dao,不具有可变参数private UserService userService = new UserServiceImpl();public void doGet(HttpServletRequest request, HttpServletResponse response) {userService.update(...);}}public class UserServiceImpl implements UserService {// 是否安全 是,调用Dao,不具有可变参数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) {// ...}}}/*题目5*/public class MyServlet extends HttpServlet {// 是否安全 不是,具有conn可变参数private UserService userService = new UserServiceImpl();public void doGet(HttpServletRequest request, HttpServletResponse response) {userService.update(...);}}public class UserServiceImpl implements UserService {// 是否安全 不是,具有conn可变参数private UserDao userDao = new UserDaoImpl();public void update() {userDao.update();}}public class UserDaoImpl implements UserDao {// 是否安全 不是,具有conn可变参数private Connection conn = null;public void update() throws SQLException {String sql = "update user set password = ? where username = ?";conn = DriverManager.getConnection("","","");// ...conn.close();}}/*题目6*/public class MyServlet extends HttpServlet {// 是否安全 但是这里是安全的// 虽然底层将conn创建在堆里,但是impl层创建了多个userDao对象,导致产生了多个conn不产生安全问题private UserService userService = new UserServiceImpl();public void doGet(HttpServletRequest request, HttpServletResponse response) {userService.update(...);}}public class UserServiceImpl implements UserService {public void update() {UserDao userDao = new UserDaoImpl();userDao.update();}}public class UserDaoImpl implements UserDao {// 是否安全 不是,具有conn可变参数private Connection = null;public void update() throws SQLException {String sql = "update user set password = ? where username = ?";conn = DriverManager.getConnection("","","");// ...conn.close();}}/*题目7*/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();}}

    经验总结扩展阅读