使用了危险的http传输方法put,使用put方法如下
PUT路径要用/结束,写入成功后,会返回201或者200,如果返回404说明没有写/
put: Map<String, Object> param = new HashMap<String, Object>(); param.put("newPwd", SHA256Util.hash(newPwd)); param.put("oldPwd", SHA256Util.hash(oldPwd)); param.put("token", token); /* StringBuffer sBuffer = new StringBuffer("http://test.yhzx.ucmed.cn/userCenterUCMED/user/changePassword"); sBuffer.append("?newPwd="+SHA256Util.hash(newPwd)); sBuffer.append("&oldPwd="+SHA256Util.hash(oldPwd)); sBuffer.append("&token="+token);*/ // 请求用户中心数据 JSONObject res = HttpRequest.sendPut( "http://test.yhzx.ucmed.cn/userCenterUCMED/user/changePassword", param, "utf-8"); public static JSONObject sendPut(String url, Map<String, Object> map, String charset) { String param = getParam(map); String reponse = Put(url, param, charset); JSONObject res=JSONObject.fromObject(reponse); return res; } public static String getParam(Map<String, Object> map) { StringBuffer sb = new StringBuffer(); // 构建请求参数 if (map != null && map.size() > 0) { Iterator it = map.entrySet().iterator(); // 定义迭代器 while (it.hasNext()) { Map.Entry er = (Entry) it.next(); sb.append(er.getKey()); sb.append("="); sb.append(er.getValue()); sb.append("&"); } } return sb.toString(); } public static String Put(String url, String param, String charset) { PrintWriter out = null; BufferedReader in = null; String result = ""; String line; StringBuffer sb = new StringBuffer(); try { String urlNameString = url + "?" + param; logger.info(urlNameString); URL realurl = new URL(urlNameString); // 打开和URL之间的连接 HttpURLConnection conn = (HttpURLConnection) realurl .openConnection(); // 设置通用的请求属性 设置请求格式 conn.setRequestProperty("contentType", charset); /*conn.setRequestProperty("content-type", "application/x-www-form-urlencoded");*/ // 申明请求方式 conn.setRequestMethod("PUT"); // 发送put请求必须设置如下两行 conn.setDoInput(true); conn.setDoOutput(true); out = new PrintWriter(conn.getOutputStream()); // flush输出流的缓冲 out.flush(); in = new BufferedReader(new InputStreamReader( conn.getInputStream(), charset)); while ((line = in.readLine()) != null) { sb.append(line); } result = sb.toString(); } catch (Exception e) { System.err.println("PUT请求出现异常!" + e); e.printStackTrace(); } finally { try { if (out != null) { out.close(); } if (in != null) { in.close(); } } catch (IOException ex) { ex.printStackTrace(); } } return result; }
在 ConcurrentHashMap 中,线程对映射表做读操作时,一般情况下不需要加锁就可以完成,对容器做结构性修改的操作才需要加锁。下面以 put 操作为例说明对 ConcurrentHashMap 做结构性修改的过程。
首先,根据 key 计算出对应的 hash 值:
清单 4.Put 方法的实现
public V put(K key, V value) { if (value == null) //ConcurrentHashMap 中不允许用 null 作为映射值 throw new NullPointerException(); int hash = hash(key.hashCode()); // 计算键对应的散列码 // 根据散列码找到对应的 Segment return segmentFor(hash).put(key, hash, value, false); }
然后,根据 hash 值找到对应的
Segment 对象:清单 5.根据 hash 值找到对应的 Segment
/** * 使用 key 的散列码来得到 segments 数组中对应的 Segment */ final Segment<K,V> segmentFor(int hash) { // 将散列值右移 segmentShift 个位,并在高位填充 0 // 然后把得到的值与 segmentMask 相“与” // 从而得到 hash 值对应的 segments 数组的下标值 // 最后根据下标值返回散列码对应的 Segment 对象 return segments[(hash >>> segmentShift) & segmentMask]; }最后,在这个 Segment 中执行具体的 put 操作:
清单 6.在 Segment 中执行具体的 put 操作
V put(K key, int hash, V value, boolean onlyIfAbsent) { lock(); // 加锁,这里是锁定某个 Segment 对象而非整个 ConcurrentHashMap try { int c = count; if (c++ > threshold) // 如果超过再散列的阈值 rehash(); // 执行再散列,table 数组的长度将扩充一倍 HashEntry<K,V>[] tab = table; // 把散列码值与 table 数组的长度减 1 的值相“与” // 得到该散列码对应的 table 数组的下标值 int index = hash & (tab.length - 1); // 找到散列码对应的具体的那个桶 HashEntry<K,V> first = tab[index]; HashEntry<K,V> e = first; while (e != null && (e.hash != hash || !key.equals(e.key))) e = e.next; V oldValue; if (e != null) { // 如果键 / 值对以经存在 oldValue = e.value; if (!onlyIfAbsent) e.value = value; // 设置 value 值 } else { // 键 / 值对不存在 oldValue = null; ++modCount; // 要添加新节点到链表中,所以 modCont 要加 1 // 创建新节点,并添加到链表的头部 tab[index] = new HashEntry<K,V>(key, hash, first, value); count = c; // 写 count 变量 } return oldValue; } finally { unlock(); // 解锁 } }注意:这里的加锁操作是针对(键的 hash 值对应的)某个具体的 Segment,锁定的是该 Segment 而不是整个 ConcurrentHashMap
。因为插入键 / 值对操作只是在这个 Segment 包含的某个桶中完成,不需要锁定整个
ConcurrentHashMap。此时,其他写线程对另外 15 个
Segment 的加锁并不会因为当前线程对这个 Segment 的加锁而阻塞。同时,所有读线程几乎不会因本线程的加锁而阻塞(除非读线程刚好读到这个 Segment 中某个HashEntry 的 value 域的值为 null,此时需要加锁后重新读取该值
)。相比较于
HashTable 和由同步包装器包装的 HashMap
每次只能有一个线程执行读或写操作,
ConcurrentHashMap 在并发访问性能上有了质的提高。在理想状态下,ConcurrentHashMap 可以支持 16 个线程执行并发写操作(如果并发级别设置为 16),及任意数量线程的读操作。
总结:
首先定位到segment:
计算hash函数:
int hash = hash(key)
//定位Segment所使用的hash算法
hash >>> segmentShift) & segmentMask
// 加锁,这里是锁定某个 Segment 对象而非整个 ConcurrentHashMap
if (c++ > threshold) // 如果超过再散列的阈值
rehash(); // 执行再散列,table 数组的长度将扩充一倍
// 定位HashEntry所使用的hash算法
int index = hash & (tab.length - 1);
接下来查找链表的头结点,如果头结点不为空的话,那么开始遍历链表,如果存在的话,就给value赋值,同时返回oldValue,如果不存在的话,就插入到链表的头结点
使用了危险的http传输方法put,使用put方法如下
PUT路径要用/结束,写入成功后,会返回201或者200,如果返回404说明没有写/
转载于:https://blog.51cto.com/eth10/1967403
关于PUT请求带参数问题:
因为tomcat默认只有post传参,put 和 delete 不支持 两种解决方案
1.修改tomcat的配置文件
2.在web.xml里面配置过滤器
httpPutFormContentFilter
org.springframework.web.filter.HttpPutFormContentFilter
httpPutFormContentFilter
/*
作者:卜可
来源:CSDN
原文:https://blog.csdn.net/q649381130/article/details/77980015
版权声明:本文为博主原创文章,转载请附上博文链接!