concurrentHashMap是线程安全且强一致性的吗?

看了文档,但是不是很明白,这个类可以在不阻塞线程的情况下提供线程安全的并发写,但是他没有对读进行同步,那么,假如读和写发生在同一个元素的时候,怎么办?这时候不做同步,那么数据肯定是脏的啊?还是我理解有错,大家都怎么使用这个类咧

8个回答

说白了ConcurrentHashMap也是加锁的 但是不是全局锁 而是 分块锁(对桶里的数据分块 按块加锁 提高并发)

IFULEYOU49
IFULEYOU49 read在删除元素的时候也可能出现问题,出现返回已删除的元素,这相当于读到了脏数据,不过,这在很多情况下不重要,比如配置缓存,数据缓存等
大约 7 年之前 回复
IFULEYOU49
IFULEYOU49 他的clear和迭代确实可能出现的情况,read在删除元素的时候也可能出现问题,这也算单个元素哦,不过确实作为key-value的话,确实够了
大约 7 年之前 回复
jinnianshilongnian
jinnianshilongnian 其实你应该知道ConcurrentHashMap的使用场景 可以看作一个key-value数据库 我们只要保证单个key-value是线程安全即可 如数据库的原子性也是类似 如果非要整个表强一致 那就等价于HashTable了
大约 7 年之前 回复
IFULEYOU49
IFULEYOU49 对,说到点子上了,为啥,每个segements是强一致的,但是整个Map不是,什么情况下出现若一致的情况
大约 7 年之前 回复
jinnianshilongnian
jinnianshilongnian /** * Removes all of the mappings from this map. */ public void clear() { final Segment<K,V>[] segments = this.segments; for (int j = 0; j < segments.length; ++j) { Segment<K,V> s = segmentAt(segments, j); if (s != null) s.clear(); } } 1、先获取Segment 然后对每一个Segment clear 因此此时是不加锁的 2、Segment的clear 是加锁的 final void clear() { lock(); try { HashEntry<K,V>[] tab = table; for (int i = 0; i < tab.length ; i++) setEntryAt(tab, i, null); ++modCount; count = 0; } finally { unlock(); } } } 3、因此每一块可认为是强一致 但整个Map不是
大约 7 年之前 回复
IFULEYOU49
IFULEYOU49 我主要关心的是read, iterator这些东西的一致性,貌似从google的结果中,发现对read, clear, iterator是弱一致性,那么是说它完全不加锁吗
大约 7 年之前 回复

单独的读写操作(get,put,putIfAbsent...)是完全线程安全且一致的,但是迭代时候则不是强一致的,迭代所遍历的不是迭代时刻的快照,而是各个segement的真是数据,所以迭代期间如有数据发生变更,如果变更的是已经遍历的segement则迭代过程不再感知这个变化,但如果变化发生在未遍历的segement,则本次迭代会感知到这个元素。另外一个基本常识,任意的组合操作,比如先get, 然后put,则不能保证强一致。此外这个类还有个特点,迭代过程中即使元素被修改,也不会抛出异常,其他一些集合则会抛出ConcurrentModificationException

IFULEYOU49
IFULEYOU49 单独的读在一个极端情况下是可能不一致的,那就是,刚好读到一个正在删除的元素,而且这个元素是因为hash冲突放到链表上的元素,除此之外,单独读写是线程安全且一致的
大约 7 年之前 回复

[code="java"] V get(Object key, int hash) {
if (count != 0) { // read-volatile
HashEntry e = getFirst(hash);
while (e != null) {
if (e.hash == hash && key.equals(e.key)) {
V v = e.value;
if (v != null)
return v;
return readValueUnderLock(e); // recheck
}
e = e.next;
}
}
return null;
}[/code]

在写的时候,是不读就为null

在读的时候时,有同步锁
[code="java"]
V readValueUnderLock(HashEntry e) {
lock();
try {
return e.value;
} finally {
unlock();
}
}
[/code]

IFULEYOU49
IFULEYOU49 咦,从你发的代码看出,这个读都有强一致性了 另外 "是不读就为null"是什么意思 能加点说明就更好了,因为我也不知道这个lock是什么lock
大约 7 年之前 回复

[code="java"]
/**

  • ConcurrentHashMap list entry. Note that this is never exported
  • out as a user-visible Map.Entry. *
  • Because the value field is volatile, not final, it is legal wrt
  • the Java Memory Model for an unsynchronized reader to see null
  • instead of initial value when read via a data race. Although a
  • reordering leading to this is not likely to ever actually
  • occur, the Segment.readValueUnderLock method is used as a
  • backup in case a null (pre-initialized) value is ever seen in
  • an unsynchronized access method. */ static final class HashEntry { final K key; final int hash; volatile V value; // <-- volatile final HashEntry next; }[/code]

按照我的理解,volatile可以保证一个线程总是能看到最后一个线程写入的数据,HashEntry的构造函数也没有escape this,这里readValueUnderLock只是用来backup的吧,实际上并不太可能会出现为null的情况

参考资料
http://stackoverflow.com/questions/12740844/why-get-method-in-concurrenthashmap-is-blocking
http://jsr166-concurrency.10961.n7.nabble.com/Numa-and-ReentrantLock-td5630.html
http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html#finalRight

IFULEYOU49
IFULEYOU49 咦,再读了一下源码,发现确实可以保证value的多线程可见性,那就不存在所谓的弱一致性了呀,而且还有readValueUnderLock做backup,那么哪里可能出现脏数据呢
大约 7 年之前 回复
IFULEYOU49
IFULEYOU49 我知道他的HashEntry数组tab是和HashEntry里的value都是volatile,但是这仍然不能保证能读到最新的数据吧,volatile不能保证数组元素是最新的,假如线程B修正了tab里的某个HashEntry,线程A在读取这个HashEntry的时候,并不能保证线程B的结构对A可见,当然,tab[index].get(hash)的value是volatile,那么读hash值应该可以保证可见性
大约 7 年之前 回复

ConcurrentHashMap 将 map中数据通过hash 散列到32个Segment 中,Segment 是 ConcurrentHashMap 一个内部类,他继承了ReentrantLock ,ConcurrentHashMap 将锁进行分化到每一个Segment中,只有对同一个Segment 元素的读写时 才会阻塞,否则是无阻塞的,这样就大大的提高了并发的执行速度。

V get(Object key, int hash) {
if (count != 0) { // read-volatile
HashEntry e = getFirst(hash);
while (e != null) {
if (e.hash == hash && key.equals(e.key)) {
V v = e.value;
if (v != null)
return v;
return readValueUnderLock(e); // recheck
}
e = e.next;
}
}
return null;

V put(K key, int hash, V value, boolean onlyIfAbsent) {
lock();
try {
int c = count;
if (c++ > threshold) // ensure capacity
rehash();
HashEntry[] tab = table;
int index = hash & (tab.length - 1);
HashEntry first = tab[index];
HashEntry 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;
            }
            else {
                oldValue = null;
                ++modCount;
                tab[index] = new HashEntry<K,V>(key, hash, first, value);
                count = c; // write-volatile
            }
            return oldValue;
        } finally {
            unlock();
        }
    }

get中的readValueUnderLock 和 put 都是互斥的 所以是安全的

检索会影响最近[color=red]完成的[/color] 更新操作的结果

所谓完成的,就是从put方法返回了

ticmy
龙四 如果put和get同时进行,put已经将元素放入底层数据结构,get此时进行也未必能看到这个put的结果。待put返回之后,再get,就一定会看到结果
大约 7 年之前 回复

ConcurrentHashMap对K/V的读写都是加锁的,是一个可重入锁(ReenTrantLock),当然这是一个Segment(片段锁),只会锁定某一个K/V,基于CAS调度,也就是与CPU的直接打交道的,使用的是NonfairSync,所以能保证最大的吞吐量.

JDK中的任何类的线程安全只针对于类内部,比如你执行如下代码
map.put(1,1)//@1
int a = map.get(1)
map.put(1,2)//@2
int b = map.get(1)
a==b? true: false
如果是单线程,那么返回的是false,如果是多线程环境,那么你要注意了.
当线程A执行完@1的时候,可能CPU调度的时候[轮到线程B],线程B执行完@2,那么a的值就为2
所以在多线程环境,同步是由程序员来控制的.至于你说的强一致性,就看你自己的理解了

a1000005aa
a1000005aa ConcurrentHashMap 本来就是为了解决并发情况下hashMap的性能而产生的,如果不使用在多线程,请使用HashMap,性能更好
大约 7 年之前 回复
a1000005aa
a1000005aa package current; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; public class TTTT { private static Map<Long, ServiceDO> widgetCacheMap = new ConcurrentHashMap<Long, ServiceDO>(); /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub for(int i=0;i<1000;i++){ Thread tt = new Thread(new Rund()); tt.start(); } } static class Rund implements Runnable{ public void run() { // TODO Auto-generated method stub test(); } public void test(){ TTTT tt = new TTTT(); tt.set(); //1. 设置值 int s1 = widgetCacheMap.get(1L).getStatus(); tt.change(); //2. 设置值 int s2 = widgetCacheMap.get(1L).getStatus(); if(s1==s2){ System.out.println(s1+":"+s2); } } } public void set() { ServiceDO ss = new ServiceDO(); ss.setStatus(1); widgetCacheMap.put(1L, ss); } public void change(){ ServiceDO ss = new ServiceDO(); ss.setStatus(2); widgetCacheMap.put(1L, ss); } }
大约 7 年之前 回复
smallbee12345
smallbee12345 除非是单例非线程安全情况,否则你上面写的代码如果在一个方法里面,无需考虑多线程安全问题。多个线程的a和b是独立的。
大约 7 年之前 回复

如读和写发生在同一个元素的时候,怎么办?这时候不做同步,那么数据肯定是脏的啊。

你理解的脏数据是有问题的,脏数据是指消费和生产的数据不一致,好比存钱和取钱,最后发现钱少了或钱多了,这就是脏数据。
而你描述的顶多算幻读,我在12:00打钱到你卡上,你12:05分才看到。幻读在任何系统都会出现,如果你一定不想有幻读,那么只有牺牲效率为代价。
这方面跟数据库的事务隔离级别就点类似。

Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
其他相关推荐
多线程环境下使用线程安全的ConcurrentHashMap代码有何问题

![图片说明](https://img-ask.csdn.net/upload/201705/23/1495507632_656868.jpg)

ConcurrenthashMap如何实现并发操作

请教一个问题, 首先在ConcurrenthashMap中预置10万条测试数据 1,我如何使用一个线程对ConcurrenthashMap作操作,先get(key),接着remove(key),直到所有数据remove,记录一下所有时间 2,我如何使用多个线程(3个线程)对ConcurrenthashMap作上面同样的操作,我需要得到两种处理方式所使用的时间 希望能给我简单的demo,谢谢了,小弟线上等待。。。

spring 里面的 bean 池为啥要用 ConcurrentHashMap

在 spring getbean() 的时候,如果是 singleton 的话, bean实例化后 会保存在 一个 ConcurrentHashMap 中, 我的问题是为什么要用 ConcurrentHashMap? 我觉得 HashMap 也可以啊。目前我自己要实现一个 简易的 bean 池, 里面的 bean 不要求线程安全,那么是不是可以直接用 HashMap 了? 期待牛人的解答

ConcurrentHashMap中内部类Segment中的count和threshold

![图片说明](https://img-ask.csdn.net/upload/201910/14/1571062410_953240.jpg) 当Segment初始化的时候闯将HashEntry数组时,大小为cap,threshold也为扩容系数*数组的大小,我的理解是根据数组实例化的个数是否大于threshold来判断是否扩容的。而在Segment类中的put方法中,明显的是判断tab中元素的个数(包括链表上的元素)和threshold比较的呢?,求解答![图片说明](https://img-ask.csdn.net/upload/201910/14/1571062481_859709.jpg)

Java concurrentHashmap 如何进行分段遍历操作

Java concurrentHashmap 如何进行分段遍历操作 如: concurrentHashmap存了1000条数据; 如何分10次,每次100条进行遍历操作 群里大神提到一种方案: 对长连接进行hash取模,分布在不同的hashmap 我的补充: 如果我想支持50万并发,就一次性的初始化500个hashmap,放到list中 对每个长连接取模,放到对应下标的hashmap中

ConcurrentHashMap( since 1.5 jdk1.8)

有几点疑问想要请教大家,不吝赐教: 1.get方法的弱一致性: get方法并没有加锁,因此也不会和put方法冲突,当多个线程同时操作该map时,有的线程get,有的线程put,因为我们并不确定put方法执行完了没(即是否写了内存),所以get不一定能够得到最新值(put还没写进去,叫最新值也不是很妥当)。但是,一旦put操作执行完,那么get一定可以感知到最新值,因为: ``` static class Node<K,V> implements Map.Entry<K,V> { final int hash; final K key; **volatile** V val; **volatile** Node<K,V> next; ``` 2.size方法,也是没有加锁,存在和get方法同样的问题。

log4j日志存入数据库的多线程并发问题

我使用Mina框架来接收多线程的数据,当我想取得创建时间(从sessionCreated()方法获得)、session的上下文信息(从messageReceived()方法获得)以及断开时间(从sessionClosed()方法获得)的时候,我使用log4j的MDC来输出到数据库。可是问题来了,因为要取得断开时间,必须得第一个线程断开后触发sessionClosed()方法取得断开时间后才能将第一个线程的所有信息才会存入到数据库;但是当第一个线程没断开,第二个线程就进来了发送数据,而且马上触发sessionClosed()线程,那么它就覆盖了第一个线程的信息了。使得本来属于第一个线程的信息取不到了。其中我使用ConcurrentHashMap来存储进入数据库前的信息 。不知道有什么更好的方法可以解决呢?

在多线程情况下,不使用同步,对同一个MAP的并发读写问题

假设有以下场景: 某一个业务要求,定时的从数据库中取出一批数据放入一个hashmap中。 有多个线程对这个MAP进行读操作。 每过一段时间(如3分钟),都会对这个MAP进行修改(put or remove) 该场景对数据的一致性没有非常严格的要求。 如何能够在不使用同步的情况下,对这个MAP进行安全的操作呢?(例如不用concurrentHashMap,或Collections.synchronizedMap) 我的想法是,每次在需要修改MAP的时候,可以创建一个旧MAP的副本,对副本进行修改后,再替换原先的MAP 例如: Map newMap = oldMap.clone(); //或者用new HashMap().putall(oldMap)来创造副本 newMap.put / remove ..... //修改map oldMap = newMap; //替换上去 这样就不会因为对同一个map的并发读写而导致快速迭代失败。有没有大神看看这样有什么潜在的问题,比如GC。。请不吝赐教>_< ( jdk 1.6 api hashMap 在迭代器创建之后,如果从结构上对映射进行修改,除非通过迭代器本身的 remove 方法,其他任何时间任何方式的修改,迭代器都将抛出 ConcurrentModificationException。因此,面对并发的修改,迭代器很快就会完全失败,而不冒在将来不确定的时间发生任意不确定行为的风险。 )

HttpSessionBindingListener ConcurrentHashMap

在springmvc项目中实现了HttpSessionBindingListener 并且在valueBound中将HttpSession加入到了public static final Map<String, Object> sessionMap = new ConcurrentHashMap<String, Object>(); 然后在controller中得到了sessionMap 并通过key获取到了某个HttpSession 不知道为什么一旦调用session.invalidate();就会报java.util.ConcurrentModificationException的错误: java.util.ConcurrentModificationException at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859) at java.util.ArrayList$Itr.next(ArrayList.java:831) at com.sihan.gmrcsubs.action.auth.SysUserAction.deleteUser(SysUserAction.java:209) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:219) at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:132) at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:745) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:686) at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80) at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:925) at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:856) at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:920) at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:827) at javax.servlet.http.HttpServlet.service(HttpServlet.java:646) at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:801) at javax.servlet.http.HttpServlet.service(HttpServlet.java:727) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) at com.alibaba.druid.support.http.WebStatFilter.doFilter(WebStatFilter.java:123) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:501) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103) at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:950) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408) at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1070) at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:611) at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.doRun(AprEndpoint.java:2440) at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.run(AprEndpoint.java:2429) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) at java.lang.Thread.run(Thread.java:745) 但是并未调用map.remmove()方法,求大神帮助 另外若通过controller方法上的request获取httpsession并调用invalidate方法,在触发HttpSessionBindingListener 的valueUnbound方法时我进行了map.remove() 却没有保存结果也是正确的

Java错误:Invalid bound statement (not found): com.vt.dao.UserDao.queryByName] with root cause

尝试写一个登录接口,然后使用postman测试时报错 ``` { "timestamp": "2019-11-28T02:01:56.696+0000", "status": 500, "error": "Internal Server Error", "message": "Invalid bound statement (not found): com.vt.dao.UserDao.queryByName", "path": "/register" } ``` 按照网上说的改了xml名字,改了代码也不行,希望大佬相助,谢谢 运行以后出现下面的错误 ``` 2019-11-28 10:01:56.638 INFO 17836 --- [nio-8080-exec-2] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet' 2019-11-28 10:01:56.638 INFO 17836 --- [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet' 2019-11-28 10:01:56.643 INFO 17836 --- [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet : Completed initialization in 5 ms 2019-11-28 10:01:56.690 ERROR 17836 --- [nio-8080-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.vt.dao.UserDao.queryByName] with root cause org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.vt.dao.UserDao.queryByName at org.apache.ibatis.binding.MapperMethod$SqlCommand.<init>(MapperMethod.java:235) ~[mybatis-3.5.3.jar:3.5.3] at org.apache.ibatis.binding.MapperMethod.<init>(MapperMethod.java:53) ~[mybatis-3.5.3.jar:3.5.3] at org.apache.ibatis.binding.MapperProxy.lambda$cachedMapperMethod$0(MapperProxy.java:98) ~[mybatis-3.5.3.jar:3.5.3] at java.base/java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1705) ~[na:na] at org.apache.ibatis.binding.MapperProxy.cachedMapperMethod(MapperProxy.java:97) ~[mybatis-3.5.3.jar:3.5.3] at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:92) ~[mybatis-3.5.3.jar:3.5.3] at com.sun.proxy.$Proxy63.queryByName(Unknown Source) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na] at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) ~[spring-aop-5.2.1.RELEASE.jar:5.2.1.RELEASE] at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198) ~[spring-aop-5.2.1.RELEASE.jar:5.2.1.RELEASE] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.2.1.RELEASE.jar:5.2.1.RELEASE] at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139) ~[spring-tx-5.2.1.RELEASE.jar:5.2.1.RELEASE] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.2.1.RELEASE.jar:5.2.1.RELEASE] at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) ~[spring-aop-5.2.1.RELEASE.jar:5.2.1.RELEASE] at com.sun.proxy.$Proxy64.queryByName(Unknown Source) ~[na:na] at com.vt.service.UserServiceImpl.UserServiceImpl.queryByName(UserServiceImpl.java:24) ~[classes/:na] at com.vt.controller.UserController.register(UserController.java:24) ~[classes/:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na] at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190) ~[spring-web-5.2.1.RELEASE.jar:5.2.1.RELEASE] at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138) ~[spring-web-5.2.1.RELEASE.jar:5.2.1.RELEASE] at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106) ~[spring-webmvc-5.2.1.RELEASE.jar:5.2.1.RELEASE] at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:888) ~[spring-webmvc-5.2.1.RELEASE.jar:5.2.1.RELEASE] at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:793) ~[spring-webmvc-5.2.1.RELEASE.jar:5.2.1.RELEASE] at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.2.1.RELEASE.jar:5.2.1.RELEASE] at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040) ~[spring-webmvc-5.2.1.RELEASE.jar:5.2.1.RELEASE] at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943) ~[spring-webmvc-5.2.1.RELEASE.jar:5.2.1.RELEASE] at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.2.1.RELEASE.jar:5.2.1.RELEASE] at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909) ~[spring-webmvc-5.2.1.RELEASE.jar:5.2.1.RELEASE] at javax.servlet.http.HttpServlet.service(HttpServlet.java:660) ~[tomcat-embed-core-9.0.27.jar:9.0.27] at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[spring-webmvc-5.2.1.RELEASE.jar:5.2.1.RELEASE] at javax.servlet.http.HttpServlet.service(HttpServlet.java:741) ~[tomcat-embed-core-9.0.27.jar:9.0.27] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-9.0.27.jar:9.0.27] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.27.jar:9.0.27] at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.27.jar:9.0.27] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.27.jar:9.0.27] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.27.jar:9.0.27] at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-5.2.1.RELEASE.jar:5.2.1.RELEASE] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.1.RELEASE.jar:5.2.1.RELEASE] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.27.jar:9.0.27] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.27.jar:9.0.27] at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-5.2.1.RELEASE.jar:5.2.1.RELEASE] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.1.RELEASE.jar:5.2.1.RELEASE] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.27.jar:9.0.27] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.27.jar:9.0.27] at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.2.1.RELEASE.jar:5.2.1.RELEASE] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.1.RELEASE.jar:5.2.1.RELEASE] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.27.jar:9.0.27] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.27.jar:9.0.27] at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202) ~[tomcat-embed-core-9.0.27.jar:9.0.27] at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) ~[tomcat-embed-core-9.0.27.jar:9.0.27] at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:526) ~[tomcat-embed-core-9.0.27.jar:9.0.27] at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139) ~[tomcat-embed-core-9.0.27.jar:9.0.27] at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) ~[tomcat-embed-core-9.0.27.jar:9.0.27] at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) ~[tomcat-embed-core-9.0.27.jar:9.0.27] at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) ~[tomcat-embed-core-9.0.27.jar:9.0.27] at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408) ~[tomcat-embed-core-9.0.27.jar:9.0.27] at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) ~[tomcat-embed-core-9.0.27.jar:9.0.27] at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:861) ~[tomcat-embed-core-9.0.27.jar:9.0.27] at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1579) ~[tomcat-embed-core-9.0.27.jar:9.0.27] at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) ~[tomcat-embed-core-9.0.27.jar:9.0.27] at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) ~[na:na] at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) ~[na:na] at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-embed-core-9.0.27.jar:9.0.27] at java.base/java.lang.Thread.run(Thread.java:834) ~[na:na] ``` UserDao.xml ``` <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.vt.dao.UserDao"> <resultMap id="BaseResultMap" type="com.vt.entity.User"> <result column="username" jdbcType="VARCHAR" property="username" /> <result column="password" jdbcType="VARCHAR" property="password" /> </resultMap> <insert id="addUser" parameterType="com.vt.entity.User"> insert into user.user values (#{username},#{password}) </insert> <select id="queryByName" resultMap="BaseResultMap" resultType="com.vt.entity.User"> select * from user.user where username = #{username} </select> </mapper> ``` UserDao类 ``` package com.vt.dao; import com.vt.entity.User; import org.springframework.stereotype.Repository; import org.apache.ibatis.annotations.Mapper; import java.util.List; @Repository @Mapper public interface UserDao { int addUser(User user); List<User>queryByName(String username); } ``` ![图片说明](https://img-ask.csdn.net/upload/201911/28/1574916176_868813.png) ![图片说明](https://img-ask.csdn.net/upload/201911/28/1574916187_417511.png)

关于jdk1.8 ConcurrentHashMap源码 get方法的问题

最近我在看 ConcurrentHashMap源码的时候,看到get()方法(源码如下图所示),其中有一条判断语句 eh < 0 , 因为 ForwardingNode和TreeBin的hash为-1和-2,所以会走这条判断语句,然后执行 return (p = e.find(h, key)) != null ? p.val : null; 如果不满足该条件则说明该节点不是头结点并且hash >= 0,往下执行while()循环。 我的疑问就是,Node、ForwardingNode和TreeBin都实现了find(),那为什么get()还需要做eh < 0的判断呢,直接 return (p = e.find(h, key)) != null ? p.val : null; 不就好了,根据e的类型执行各自的find()?,该判断和while()循环存在的道理是什么呢? ![图片说明](https://img-ask.csdn.net/upload/201708/31/1504149373_380650.png)

求高手帮我解惑一下concurrentHashMap的问题

import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; public class ConcurrentHashMapTest { private static final ConcurrentMap<String, String> factory = new ConcurrentHashMap<String, String>(); public static void main(String[] args) { for(int i=0;i<10;i++){ new Thread(i+""){ public void run(){ String tf = factory.get("wang"); if (tf == null) { try { Thread.sleep((int)(Math.random()*1000)); factory.put("wang", this.getName()); Thread.sleep((int)(Math.random()*1000)); } catch (Throwable e) { e.printStackTrace(); } } System.out.println(this.getName()+"_"+factory.get("wang")); } }.start(); } } } 上面这段代码中concurrentHashMap好像没起到作用,有高手帮忙解惑下吗

多线程读数据库操作,为什么我的代码执行起来比原来还慢呢

/** * 查询 应用系统 各表的记录总数 * * @param url 数据源地址 * @param userName 数据源登陆用户名 * @param password 数据源密码 * @param tableNames 表名 List * @return Map < 表名,表下数据行数> */ static class CountThread implements Runnable{ CountThread(String tableName){ this.tableName=tableName; } static void setConnection(Connection connection) { CountThread.connection = connection; } static void setReMap(ConcurrentHashMap map){ CountThread.reMap=map; } static void setThreadCount(CountDownLatch countDownLatch) { CountThread.countDownLatch = countDownLatch; } private static CountDownLatch countDownLatch; private static ConcurrentHashMap<String,String> reMap; private static Connection connection; private String tableName; @Override public void run() { String sql = "SELECT COUNT(1) num FROM " + tableName; System.out.println(sql); try { PreparedStatement stmt = connection.prepareStatement(sql); ResultSet tablesRest = stmt.executeQuery(); while (tablesRest.next()) { String count = tablesRest.getString("num"); reMap.put(tableName, count); } tablesRest.close(); tablesRest = null; countDownLatch.countDown(); } catch (SQLException e) { log.error(e.getMessage()); reMap.put(tableName, "0"); } } } public static Map<String, String> conutRows(String url, String userName, String password, List<String> tableNames) { int size=tableNames.size(); Date start=new Date(); ConcurrentHashMap<String, String> reMap = new ConcurrentHashMap<>(size); CountDownLatch countDownLatch=new CountDownLatch(size); try (Connection connection = DriverManager.getConnection(url, userName, password)) { CountThread.setConnection(connection); CountThread.setReMap(reMap); CountThread.setThreadCount(countDownLatch); for(String tableName:tableNames){ CountThread thread = new CountThread(tableName); thread.run(); } countDownLatch.await(); // sql.append(" SELECT "); // for (String tableName : tableNames) { // sql.append(" " + tableName + "b.num " + tableName + "a ,"); //字符串拼接 表名+a 拼接成表别名 // } // // //删除多余的一个 , // sql.deleteCharAt(sql.length() - 1); // sql.append(" FROM "); // //子查询 ,分别统计表字段数 // for (String tableName : tableNames) { // sql.append(" ( SELECT COUNT(*) num FROM "); // sql.append(tableName); // sql.append(" ) " + tableName + "b ,"); // } // //删除多余的一个 , // sql.deleteCharAt(sql.length() - 1); // System.out.println(sql); // //使用sql语句进行查询获取结果集 // PreparedStatement stmt = connection.prepareStatement(sql.toString()); // ResultSet tablesRest = stmt.executeQuery(); // //对结果进行遍历,此处结果集实际应只有一行数据 // while (tablesRest.next()) { // for (String tableName : tableNames) { // String count = tablesRest.getString(tableName + "a"); // reMap.put(tableName, count); // } // } // tablesRest.close(); // tablesRest = null; } catch (Exception e) { log.error(e.getMessage()); throw new RuntimeException("数据源连接失败"); } Date end=new Date(); long costTime = (end.getTime()-start.getTime()); System.out.println("******************************************"+costTime+"**************************"); return reMap; }

concurrentHashMap 构造方法

int c = initialCapacity / ssize; if (c * ssize < initialCapacity) ++c; int cap = MIN_SEGMENT_TABLE_CAPACITY; while (cap < c) cap <<= 1; 不太懂这一段是干嘛的,不清楚++c什么情况下会发生,还有cap就是hashEntry的size吗?

关于JAVA线程池的一个问题,请各位大虾指教

各位大虾,兄弟我最近用JAVA写了一个应用程序,其中用到了线程。现在的问题是:如果不使用线程池,则结果正确(测试了多次);若使用线程池,则结果一般不正确(结果中有时多出一些数据,有时少些数据)。 代码太长,不能全部贴出,只能贴出其基础逻辑。请高手指点改进方向或问题可能存在哪些方面。多谢! 附加信息(不知是否有用):兄弟机器的处理器为Intel(R) Core(TM) i5-5200U CPU @ 2.2GHz 2.19GHz 哪位大虾的回答如果真的有用,我会想办法追加C币,绝不食言! public class PieceUpStarter { ... public static ConcurrentHashMap<Integer, Node> map = new ConcurrentHashMap<Integer, Node>(); public static ConcurrentHashMap<Integer, TempTag> ttMap = new ConcurrentHashMap<Integer, TempTag>(); public static ConcurrentHashMap<Integer, FinalTag> ftMap = new ConcurrentHashMap<Integer, FinalTag>(); public static ExecutorService pool = Executors.newFixedThreadPool(5); public static void main(String[] args) { ... new Search().visit(map); ... } } class SixDegreeBFS extends Thread { ConcurrentHashMap<Integer, Node> map = null; int i = 0; public SixDegreeBFS(ConcurrentHashMap<Integer, Node> map, int i) { this.map = map; this.i = i; } public void run() { if (map.get(i).getVisited() == 0) { ... } else { ... } } } class Search { void visit(ConcurrentHashMap<Integer, Node> map) { ... for (Integer i : map.keySet()) { Thread thread = new SixDegreeBFS(map, i.intValue()); PieceUpStarter.pool.submit(thread); } } }

web scoket在线聊天,服务连接失败

# 这是java里的代码 package com.webSocket; import net.sf.json.JSONObject; import javax.websocket.OnClose; import javax.websocket.OnMessage; import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.server.PathParam; import javax.websocket.server.ServerEndpoint; import java.io.IOException; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import javax.websocket.*; /** * @ServerEndpoint 注解是一个类层次的注解,它的功能主要是将目前的类定义成一个websocket服务器端, * 注解的值将被用于监听用户连接的终端访问URL地址,客户端可以通过这个URL来连接到WebSocket服务器端 */ @ServerEndpoint(value = "/webSocketOneToOne/{param}") public class WebSocketOneToOne { // 静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。 private static int onlineCount; //实现服务端与单一客户端通信的话,可以使用Map来存放,其中Key为用户标识 private static Map<String,WebSocketOneToOne> connections = new ConcurrentHashMap<>(); // 与某个客户端的连接会话,需要通过它来给客户端发送数据 private Session session; private String role; private String socketId; /** * 连接建立成功调用的方法 * * @param session * 可选的参数。session为与某个客户端的连接会话,需要通过它来给客户端发送数据 */ @OnOpen public void onOpen(@PathParam("param") String param, Session session) { this.session = session; String[] arr = param.split(","); this.role = arr[0]; //用户标识 this.socketId = arr[1]; //会话标识 connections.put(role,this); //添加到map中 addOnlineCount(); // 在线数加 System.out.println("有新连接加入!新用户:"+role+",当前在线人数为" + getOnlineCount()); } /** * 连接关闭调用的方法 */ @OnClose public void onClose() { connections.remove(role); // 从map中移除 subOnlineCount(); // 在线数减 System.out.println("有一连接关闭!当前在线人数为" + getOnlineCount()); } /** * 收到客户端消息后调用的方法 * * @param message * 客户端发送过来的消息 * @param session * 可选的参数 */ @OnMessage public void onMessage(String message, Session session) { System.out.println("来自客户端的消息:" + message); JSONObject json=JSONObject.fromObject(message); String string = null; //需要发送的信息 String to = null; //发送对象的用户标识 if(json.has("message")){ string = (String) json.get("message"); } if(json.has("role")){ to = (String) json.get("role"); } send(string,role,to,socketId); } /** * 发生错误时调用 * * @param session * @param error */ @OnError public void onError(Session session, Throwable error) { System.out.println("发生错误"); error.printStackTrace(); } //发送给指定角色 public static void send(String msg,String from,String to,String socketId){ try { //to指定用户 WebSocketOneToOne con = connections.get(to); if(con!=null){ if(socketId==con.socketId||con.socketId.equals(socketId)){ con.session.getBasicRemote().sendText(from+"说:"+msg); } } //from具体用户 WebSocketOneToOne confrom = connections.get(from); if(confrom!=null){ if(socketId==confrom.socketId||confrom.socketId.equals(socketId)){ confrom.session.getBasicRemote().sendText(from+"说:"+msg); } } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public static synchronized int getOnlineCount() { return onlineCount; } public static synchronized void addOnlineCount() { WebSocketOneToOne.onlineCount++; } public static synchronized void subOnlineCount() { WebSocketOneToOne.onlineCount--; } } ``` # 这是前段页面代码 <%-- Created by IntelliJ IDEA. User: Administrator Date: 2019/10/9 0009 Time: 下午 4:19 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <script> var websocket = null; //判断当前浏览器是否支持WebSocket if ('WebSocket' in window) { var url = "ws://localhost:8080/webSocket/webSocketOneToOne/1,123" websocket = new WebSocket(url); } else { alert('当前浏览器 Not support websocket') } //连接发生错误的回调方法 websocket.onerror = function() { setMessageInnerHTML("WebSocket连接发生错误"); }; //连接成功建立的回调方法 websocket.onopen = function() { setMessageInnerHTML("WebSocket连接成功"); } //接收到消息的回调方法 websocket.onmessage = function(event) { console.log("回调信息",event.data) setMessageInnerHTML(event.data); } //连接关闭的回调方法 websocket.onclose = function() { setMessageInnerHTML("WebSocket连接关闭"); } //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。 window.onbeforeunload = function() { closeWebSocket(); } //将消息显示在网页上 function setMessageInnerHTML(innerHTML) { document.getElementById('message').innerHTML += innerHTML + '<br/>'; } //关闭WebSocket连接 function closeWebSocket() { websocket.close(); } //发送消息 function send() { var message = document.getElementById('text').value; //message作为发送的信息,role作为发送的对象标识,socketId是此次会话的标识 websocket.send(JSON.stringify({'message': message, 'role': '2', 'socketId': "123"})); } </script> <input id="text" type="text" /> <button οnclick="send()">发送消息</button> <button οnclick="closeWebSocket()">关闭WebSocket连接</button> <div id="message"></div> </body> </html> ``` # 这是依赖 ``` <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.7</maven.compiler.source> <maven.compiler.target>1.7</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <dependency> <groupId>javax</groupId> <artifactId>javaee-api</artifactId> <version>7.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.47</version> </dependency> <dependency> <groupId>net.sf.json-lib</groupId> <artifactId>json-lib-ext-spring</artifactId> <version>1.0.2</version> </dependency> </dependencies> ``` ![图片说明](https://img-ask.csdn.net/upload/201910/09/1570619693_439462.png) 运行之后就是这样![图片说明](https://img-ask.csdn.net/upload/201910/09/1570619784_298966.png) ``` ```

从ConcurrentHashMap中取数据时,遇到很怪异的问题

这是我的一段代码: public UserConnection getUserConnectionByToken(Token token) { // TODO Auto-generated method stub for (Iterator<Token> iter = (Iterator<Token>) TransactionManagerImpl.userConnections .keySet().iterator(); iter.hasNext();) { Token token1 = iter.next(); if(token1.equals(token)){ return userConnections.get(token1); } } return (UserConnection)userConnections.get(token); } 其中userConnections是一个ConcurrentHashMap,里面的key是Token对象,value是UserConnection 对象,这是webservice服务端的一个方法,token是在客户端传过来的,都实现了序列化,但是在服务端处理的时候,直接 userConnections.get(token)却取不出来,但是通过迭代判断if(token1.equals(token)){return userConnections.get(token1);}却能取出来,这是怎么回事儿呢,哪位帮解释一下?

多线程更新静态数据的同步问题

在做一个程序,启动时从数据库读出静态数据存储到一个静态变量HashMap中, 提供给多个线程进行读操作,然后每隔一段时间(比如30分钟)再次从数据库更新 数据到此HashMap中,这样的逻辑需要怎样的锁来实现呢?是否应该用读写锁? 另外如何才能提高效率,同时保证线程安全?如果存储数据的容器是List又如何 实现? 更新HashMap线程逻辑代码: [code="java"] public void updateData() { // MyHashData就是存储静态数据HashMap<String, String> // 是不是应该用ConcurrentHashMap? // loadData是读取静态数据的函数,这样直接返回会不会有问题 // 是不是应该MyHashData直接调用put函数来读取数据? // 如何加锁? MyHashData = loadData(); } [/code] 其他线程逻辑代码: [code="java"] public void checkData() { // 如何加锁? if (MyHashData.containsKey(key)) { // 处理过程 ... } } [/code]

我花了一夜用数据结构给女朋友写个H5走迷宫游戏

文章目录起因分析画线(棋盘)画迷宫方块移动结语 先看效果图(在线电脑尝试地址http://biggsai.com/maze.html): 起因 又到深夜了,我按照以往在公众号写着数据结构!这占用了我大量的时间!我的超越妹妹严重缺乏陪伴而 怨气满满! 超越妹妹时常埋怨,认为数据结构这么抽象难懂的东西没啥作用,常会问道:天天写这玩意,有啥作用。而我答道:能干事情多了,比如写个小游戏啥的! 当我

花了20分钟,给女朋友们写了一个web版群聊程序

WebSocket详解 WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。 WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。可以说WebSocket的出现,使得浏览器具备了实时双

对计算机专业来说学历真的重要吗?

我本科学校是渣渣二本,研究生学校是985,现在毕业五年,校招笔试、面试,社招面试参加了两年了,就我个人的经历来说下这个问题。 这篇文章很长,但绝对是精华,相信我,读完以后,你会知道学历不好的解决方案,记得帮我点赞哦。 先说结论,无论赞不赞同,它本质就是这样:对于技术类工作而言,学历五年以内非常重要,但有办法弥补。五年以后,不重要。 目录: 张雪峰讲述的事实 我看到的事实 为什么会这样

有哪些让程序员受益终生的建议

从业五年多,辗转两个大厂,出过书,创过业,从技术小白成长为基层管理,联合几个业内大牛回答下这个问题,希望能帮到大家,记得帮我点赞哦。 敲黑板!!!读了这篇文章,你将知道如何才能进大厂,如何实现财务自由,如何在工作中游刃有余,这篇文章很长,但绝对是精品,记得帮我点赞哦!!!! 一腔肺腑之言,能看进去多少,就看你自己了!!!   目录: 在校生篇: 为什么要尽量进大厂? 如何选择语言及方

linux系列之常用运维命令整理笔录

本博客记录工作中需要的linux运维命令,大学时候开始接触linux,会一些基本操作,可是都没有整理起来,加上是做开发,不做运维,有些命令忘记了,所以现在整理成博客,当然vi,文件操作等就不介绍了,慢慢积累一些其它拓展的命令,博客不定时更新 文章目录一、系统监控1、free命令2、ulimit命令3、top命令4、df命令5、ps命令二、文件操作1、tail命令2、ll -ah三、网络通信1、ne

大学四年,我把私藏的自学「学习网站/实用工具」都贡献出来了

我应该学哪些方向?要学习哪些知识?怎么学习,看视频还是做项目?要学好编程,给你一些学习网站也好、实用工具也好,但前提是你知道如何去学习它。对于学习,特别是自学,善于搜索网上的一些资源来辅助,还是非常有必要的,下面我就把这几年私藏的各种资源,网站贡献出来给你们。 注意:文中分享的资源小鹿全部给你整理好了,如果想去获取,直接获取即可,如果觉得文章不错,转发、点赞、评论,谢谢你,嘿嘿! 一、视频学

中国麻将:世界上最早的区块链项目

                                      中国麻将:世界上最早的区块链项目 最近区块链这个玩意又被市场搞的很是火热,相信大部分人都不太清楚这玩意到底是怎么样的一个概念,它来了,它来了,它到底是啥~  国家都开始发文支持了,下面是一个通俗易懂的例子:中国麻将。       甲首先发起一个申请,我要打麻将,组建一个麻将局,这就相当于创建一个区块,这个区块会被广播

比特币原理详解

一、什么是比特币 比特币是一种电子货币,是一种基于密码学的货币,在2008年11月1日由中本聪发表比特币白皮书,文中提出了一种去中心化的电子记账系统,我们平时的电子现金是银行来记账,因为银行的背后是国家信用。去中心化电子记账系统是参与者共同记账。比特币可以防止主权危机、信用风险。其好处不多做赘述,这一层面介绍的文章很多,本文主要从更深层的技术原理角度进行介绍。 二、问题引入  假设现有4个人

Python 基础(一):入门必备知识

目录1 标识符2 关键字3 引号4 编码5 输入输出6 缩进7 多行8 注释9 数据类型10 运算符10.1 常用运算符10.2 运算符优先级 1 标识符 标识符是编程时使用的名字,用于给变量、函数、语句块等命名,Python 中标识符由字母、数字、下划线组成,不能以数字开头,区分大小写。 以下划线开头的标识符有特殊含义,单下划线开头的标识符,如:_xxx ,表示不能直接访问的类属性,需通过类提供

兼职程序员一般可以从什么平台接私活?

这个问题我进行了系统性的总结,以下将进行言简意赅的说明和渠道提供,希望对各位小猿/小媛们有帮助~ 根据我们的经验,程序员兼职主要分为三种:兼职职位众包、项目整包和自由职业者驻场。 所谓的兼职职位众包,指的是需求方这边有自有工程师配合,只需要某个职位的工程师开发某个模块的项目。比如开发一个 app,后端接口有人开发,但是缺少 iOS 前端开发工程师,那么他们就会发布一个职位招聘前端,来配合公司一

程序员接私活怎样防止做完了不给钱?

首先跟大家说明一点,我们做 IT 类的外包开发,是非标品开发,所以很有可能在开发过程中会有这样那样的需求修改,而这种需求修改很容易造成扯皮,进而影响到费用支付,甚至出现做完了项目收不到钱的情况。 那么,怎么保证自己的薪酬安全呢? 我们在开工前,一定要做好一些证据方面的准备(也就是“讨薪”的理论依据),这其中最重要的就是需求文档和验收标准。一定要让需求方提供这两个文档资料作为开发的基础。之后开发

《吊打面试官》系列-Redis基础知识

你知道的越多,你不知道的越多点赞在看,养成习惯 https://github.com/java…已经开源,有面试脑图 前言 Redis在互联网技术存储方面使用如此广泛,几乎所有的后端技术面试官都要在Redis的使用和原理方面对小伙伴们进行360°的刁难。作为一个在互联网公司面一次拿一次offer的面霸(请允许我使用一下夸张的修辞手法),打败了无数竞争对手,每次都只能看到无数落寞的身影失

Python十大装B语法

Python 是一种代表简单思想的语言,其语法相对简单,很容易上手。不过,如果就此小视 Python 语法的精妙和深邃,那就大错特错了。本文精心筛选了最能展现 Python 语法之精妙的十个知识点,并附上详细的实例代码。如能在实战中融会贯通、灵活使用,必将使代码更为精炼、高效,同时也会极大提升代码B格,使之看上去更老练,读起来更优雅。 1. for - else 什么?不是 if 和 else 才

数据库优化 - SQL优化

前面一篇文章从实例的角度进行数据库优化,通过配置一些参数让数据库性能达到最优。但是一些“不好”的SQL也会导致数据库查询变慢,影响业务流程。本文从SQL角度进行数据库优化,提升SQL运行效率。 判断问题SQL 判断SQL是否有问题时可以通过两个表象进行判断: 系统级别表象 CPU消耗严重 IO等待严重 页面响应时间过长

《吊打面试官》系列-缓存雪崩、击穿、穿透

你知道的越多,你不知道的越多 点赞再看,养成习惯 https://github.com/java…已经开源,有面试脑图 前言 Redis在互联网技术存储方面使用如此广泛,几乎所有的后端技术面试官都要在Redis的使用和原理方面对小伙伴们进行360°的刁难。作为一个在互联网公司面一次拿一次offer的面霸(请允许我使用一下夸张的修辞手法),打败了无数竞争对手,每次都只能看到无数落

面试官:你连RESTful都不知道我怎么敢要你?

面试官:了解RESTful吗? 我:听说过。 面试官:那什么是RESTful? 我:就是用起来很规范,挺好的 面试官:是RESTful挺好的,还是自我感觉挺好的 我:都挺好的。 面试官:… 把门关上。 我:… 要干嘛?先关上再说。 面试官:我说出去把门关上。 我:what ?,夺门而去 文章目录01 前言02 RESTful的来源03 RESTful6大原则1. C-S架构2. 无状态3.统一的接

论文读不懂怎么办?

王树义读完需要18分钟速读仅需6分钟悄悄告诉你几个窍门。1   痛苦做科研,不能不读论文。但是,我见过不少研究生,论文都读得愁眉苦脸的。这其中,自然有因为拖延的关系。例如教授布

为啥国人偏爱Mybatis,而老外喜欢Hibernate/JPA呢?

关于SQL和ORM的争论,永远都不会终止,我也一直在思考这个问题。昨天又跟群里的小伙伴进行了一番讨论,感触还是有一些,于是就有了今天这篇文。 声明:本文不会下关于Mybatis和JPA两个持久层框架哪个更好这样的结论。只是摆事实,讲道理,所以,请各位看官勿喷。 一、事件起因 关于Mybatis和JPA孰优孰劣的问题,争论已经很多年了。一直也没有结论,毕竟每个人的喜好和习惯是大不相同的。我也看

项目中的if else太多了,该怎么重构?

介绍 最近跟着公司的大佬开发了一款IM系统,类似QQ和微信哈,就是聊天软件。我们有一部分业务逻辑是这样的 if (msgType = "文本") { // dosomething } else if(msgType = "图片") { // doshomething } else if(msgType = "视频") { // doshomething } else { // dosho

解读!10篇人机交互领域高引论文合集

作者:肖健   哈尔滨工程大学 ACM SIGCHI会议是人机交互领域最顶级的国际会议(CCF中国计算机学会认定的A类会议),受到了学术界与工业界的广泛关注与重视。 我们收集整理了CHI 2016年至2018年来的高引论文,进行了简单解读,供各位小伙伴参考。 另外,THU AI TR 2019年第七期—人工智能之人机交互报告,马上就要跟大家见面了,欢迎关注!   CHI-2018年 V

“狗屁不通文章生成器”登顶GitHub热榜,分分钟写出万字形式主义大作

一、垃圾文字生成器介绍 最近在浏览GitHub的时候,发现了这样一个骨骼清奇的雷人项目,而且热度还特别高。 项目中文名:狗屁不通文章生成器 项目英文名:BullshitGenerator 根据作者的介绍,他是偶尔需要一些中文文字用于GUI开发时测试文本渲染,因此开发了这个废话生成器。但由于生成的废话实在是太过富于哲理,所以最近已经被小伙伴们给玩坏了。 他的文风可能是这样的: 你发现,

程序员:我终于知道post和get的区别

IT界知名的程序员曾说:对于那些月薪三万以下,自称IT工程师的码农们,其实我们从来没有把他们归为我们IT工程师的队伍。他们虽然总是以IT工程师自居,但只是他们一厢情愿罢了。 此话一出,不知激起了多少(码农)程序员的愤怒,却又无可奈何,于是码农问程序员。 码农:你知道get和post请求到底有什么区别? 程序员:你看这篇就知道了。 码农:你月薪三万了? 程序员:嗯。 码农:你是怎么做到的? 程序员:

《程序人生》系列-这个程序员只用了20行代码就拿了冠军

你知道的越多,你不知道的越多 点赞再看,养成习惯GitHub上已经开源https://github.com/JavaFamily,有一线大厂面试点脑图,欢迎Star和完善 前言 这一期不算《吊打面试官》系列的,所有没前言我直接开始。 絮叨 本来应该是没有这期的,看过我上期的小伙伴应该是知道的嘛,双十一比较忙嘛,要值班又要去帮忙拍摄年会的视频素材,还得搞个程序员一天的Vlog,还要写BU

程序员把地府后台管理系统做出来了,还有3.0版本!12月7号最新消息:已在开发中有github地址

第一幕:缘起 听说阎王爷要做个生死簿后台管理系统,我们派去了一个程序员…… 996程序员做的梦: 第一场:团队招募 为了应对地府管理危机,阎王打算找“人”开发一套地府后台管理系统,于是就在地府总经办群中发了项目需求。 话说还是中国电信的信号好,地府都是满格,哈哈!!! 经常会有外行朋友问:看某网站做的不错,功能也简单,你帮忙做一下? 而这次,面对这样的需求,这个程序员

小白都能看得懂的java虚拟机内存模型

目录  一、虚拟机 二、虚拟机组成 1.栈 栈帧 2.程序计数器 3.方法区 对象组成 4.本地方法栈 5.堆 GC GC案例  一、虚拟机 ​ 同样的java代码在不同平台生成的机器码肯定是不一样的,因为不同的操作系统底层的硬件指令集是不同的。 同一个java代码在windows上生成的机器码可能是0101.......,在linux上生成的可能是1100.

面试官如何考察你的思维方式?

1.两种思维方式在求职面试中,经常会考察这种问题:北京有多少量特斯拉汽车? 某胡同口的煎饼摊一年能卖出多少个煎饼? 深圳有多少个产品经理? 一辆公交车里能装下多少个乒乓球? 一

so easy! 10行代码写个"狗屁不通"文章生成器

前几天,GitHub 有个开源项目特别火,只要输入标题就可以生成一篇长长的文章。背后实现代码一定很复杂吧,里面一定有很多高深莫测的机器学习等复杂算法不过,当我看了源代码之后这程序不到50

MySQL数据库总结

一、数据库简介 二、MySQL数据类型 三、Sql语句 &nbsp;&nbsp;&nbsp;&nbsp;(1)Sql语句简介 &nbsp;&nbsp;&nbsp;&nbsp;(2)数据定义语言DDLcreate,alter,drop &nbsp;&nbsp;&nbsp;&nbsp;(3)数据操纵语言DMLupdate,insert,delete &nbsp;&nbsp;&nbsp;&nbsp;(

记一次腾讯面试:进程之间究竟有哪些通信方式?如何通信? ---- 告别死记硬背

有一次面试的时候,被问到进程之间有哪些通信方式,不过由于之前没深入思考且整理过,说的并不好。想必大家也都知道进程有哪些通信方式,可是我猜很多人都是靠着”背“来记忆的,所以今天的这篇文章,讲给大家详细着讲解他们是如何通信的,让大家尽量能够理解他们之间的区别、优缺点等,这样的话,以后面试官让你举例子,你也能够顺手拈来。 1、管道 我们来看一条 Linux 的语句 netstat -tulnp | gr

20行Python代码爬取王者荣耀全英雄皮肤

引言 王者荣耀大家都玩过吧,没玩过的也应该听说过,作为时下最火的手机MOBA游戏,咳咳,好像跑题了。我们今天的重点是爬取王者荣耀所有英雄的所有皮肤,而且仅仅使用20行Python代码即可完成。 准备工作 爬取皮肤本身并不难,难点在于分析,我们首先得得到皮肤图片的url地址,话不多说,我们马上来到王者荣耀的官网: 我们点击英雄资料,然后随意地选择一位英雄,接着F12打开调试台,找到英雄原皮肤的图片

立即提问
相关内容推荐