zoukankan      html  css  js  c++  java
  • DRP之synchronized及锁的思考

       写这篇博文的背景,是发生在前段时间的评教系统,评教系统出现瘫痪,为了找出问题,大家加班加点,找出的问题就是一个字:“锁”,由于评教系统会频繁的出现学生对数据库的查询,修改,查询,修改,这样就产生了一个进程资源不够,产生死锁!

       在进行DRP项目中,id生成器的原理与我原先评教系统的机制是大致相同的,id加1,然后接着查询id,反复进行此操作,如果一个人,小数据量的在进行,系统不会报错,但是,米老师一直提出“大数据”,我们做出的软件不是一个人在使用。如何避免这样的问题。看下面的代码:

      

    package com.bjpowernode.drp.util;
    
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    
    /**
     * id生成器
     * @author Administrator
     *
     */
    public class IdGenerator {
    
    	/**
    	 * 根据表名生成该表的序列
    	 * @param tableName
    	 * @return 返回生成的序列
    	 */
    	<span style="color:#ff0000;">//public static synchronized int generate(String tableName) {
    	//public synchronized int generate(String tableName) {
    		//synchronized(this) {</span>
    	public static int generate(String tableName) {
    		//使用数据库的悲观锁for update
    		<span style="color:#ff0000;">String sql = "select value from t_table_id where table_name=? for update";</span>
    		Connection conn = null;
    		PreparedStatement pstmt = null;
    		ResultSet rs = null;
    		int value = 0;
    		try {
    			conn = DbUtil.getConnection();
    			//开始事务
    			DbUtil.beginTransaction(conn);
    			pstmt = conn.prepareStatement(sql);
    			pstmt.setString(1, tableName);
    			rs = pstmt.executeQuery();
    			if (!rs.next()) {
    				throw new RuntimeException();
    			}
    			value = rs.getInt("value");
    			value++; //自加
    			modifyValueField(conn, tableName, value);
    			//提交事务
    			DbUtil.commitTransaction(conn);
    		}catch(Exception e) {
    			e.printStackTrace();
    			//回滚事务
    			DbUtil.rollbackTransaction(conn);
    			throw new RuntimeException();
    		}finally {
    			DbUtil.close(rs);
    			DbUtil.close(pstmt);
    			DbUtil.resetConnection(conn); //重置Connection的状态
    			DbUtil.close(conn);
    		}
    		return value;
    	}
    	
    	/**
    	 * 根据表名更新序列字段的值
    	 * @param conn
    	 * @param tableName
    	 * @param value
    	 */
    	private static void modifyValueField(Connection conn, String tableName, int value) 
    	throws SQLException {
    		String sql = "update t_table_id set value=? where table_name=?";
    		PreparedStatement pstmt = null;
    		try {
    			pstmt = conn.prepareStatement(sql);
    			pstmt.setInt(1, value);
    			pstmt.setString(2, tableName);
    			pstmt.executeUpdate();
    		}finally {
    			DbUtil.close(pstmt);
    		}
    	} 
    	
    	public static void main(String[] args) {
    		int retValue = IdGenerator.generate("t_client");
    		System.out.println(retValue);
    	}
    }
        请看上面代码中红色部分,static synchronized与synchronized以及synchronized(this)的区别(如果大家想看详细的介绍请看柳波师哥的博客点击打开链接):

       1.synchronized static是某个类的范围,synchronized static 防止多个线程同时访问这个 类中的synchronized static 方法。它可以对类的所有对象实例起作用。 synchronized 是某实例的范围,synchronized 防止多个线程同时访问这个实例中的synchronized 方法。
       2.synchronized方法与synchronized(this)代码快的区别
            synchronized methods(){} 与synchronized(this){}之间没有什么区别,只是synchronized methods(){} 便于阅读理解,而synchronized(this){}可以更精确的控制冲突限制访问区域,有时候表现更高效率。
       3.synchronized关键字是不能继承的

        这里我想说一下关于死锁出现的情况以及解决的方案,大家看我的代码中红色的查询语句,

        我在cmd窗口中实验了一下:


      回车以后是没有提交数据的!


       在另一个cmd窗口中,看看在红色区域是没有任何数据的!


      出现上面的原因是在第一个窗口中锁住了数据库

      那么第二个cmd窗口如何访问数据呢,在第一个窗口中提交事务或者回滚实务如下图:


      当提交完成后在第二个窗口中就会自动出现下图:


         上面在查询语句中加入了一个for update 这叫做悲观锁。

        锁的概念在软考,操作系统,进程,线程和我们最近的评教系统中,都运用到了,如果将来以后做大数据,我相信锁的运用更是必不可少的!

    
       
    
    
  • 相关阅读:
    ABP之动态WebAPI
    ssh下常用操作汇总(good)
    XP下类似%windir% %userprofile% 的变量的说明(转)
    Cannot update paths and switch to branch at the same time(转)
    git branch(转)
    Git提交代码的处理流程(转)
    Android锁定EditText内容和随机生成验证码
    Android L下载
    vi 命令 使用方法
    Openfire开发配置,Openfire源码配置,OpenFire二次开发配置
  • 原文地址:https://www.cnblogs.com/xzpblog/p/5117948.html
Copyright © 2011-2022 走看看