我想使用ConcurrentHashMap让一个线程定期从地图中删除一些项目,并使用其他线程同时从地图中放置和获取项目.
我正在使用map.entrySet().removeIf(lambda)删除线程.我想知道我可以对它的行为做出什么假设.我可以看到该removeIf方法使用迭代器来遍历地图中的元素,检查给定的条件,然后在需要时使用它们将其删除iterator.remove().
文档提供了有关ConcurrentHashMap迭代器行为的一些信息:
类似地,Iterators,Spliterators和Enumerations在迭代器/枚举的创建时或之后的某个时刻返回反映哈希表状态的元素.嘿不要抛出ConcurrentModificationException.但是,迭代器设计为一次只能由一个线程使用.
由于整个removeIf调用发生在一个线程中,我可以确定迭代器当时不被多个线程使用.我仍然想知道下面描述的事件是否可行:
'A'->0map.entrySet().removeIf(entry->entry.getValue()==0) .iteratator()内部removeIf呼叫,并获得迭代器反映了收集的当前状态map.put('A', 1) 'A'->0映射(迭代器反映旧状态),因为0==0它是true,它决定从地图中删除A键.'A'->1但删除线程看到旧值,0并且'A' ->1条目被删除,即使它不应该.地图是空的.我可以想象,实施可以通过多种方式防止这种行为.例如:可能迭代器不反映put/remove操作,但总是反映值更新,或者迭代器的remove方法可能会检查整个映射(键和值)是否仍然存在于映射中,然后才调用键上的remove.我找不到任何有关这些事情的信息,我想知道是否有一些东西可以使用例安全.
java multithreading concurrenthashmap java.util.concurrent concurrentmodification
最近我使用一些简单的Java代码来使用main快速测试我编写的代码的方法.我最终遇到了两个类似的类:
public class A {
public static void main(String[] args) {
// code here
}
}
public class B extends A {
public static void main(String[] args) throws IOException {
// code here
}
}
Run Code Online (Sandbox Code Playgroud)
我很惊讶代码停止编译,Eclipse抱怨说Exception IOException is not compatible with throws clause in A.main(String[]).
好吧,这两个方法都是静态的,而main函数B只是隐藏了一个A,所以我认为它们之间完全没有关系.在静态方法我们没有多态性与呼叫被绑定到编译过程中的具体方法的实现,因此我不明白,为什么main在B不能乱扔未在声明例外main的签名A.
为什么Java设计者决定强制执行这样的约束,如果编译器没有强制执行约束,它会在什么情况下导致问题呢?
今天我一直在努力找到一个合适的解决方案来设置一个包含Java和Scala代码的maven项目(它们之间有双向依赖关系).
我发现的解决方案通常包括在阶段调用scala-maven-plugin或maven-scala-plugin,process-resources以便它在默认的maven编译器插件之前运行(例如:http://www.hascode.com/2012/03 /片段-混合-斯卡拉的Java-IN-A-Maven的项目/,https://itellity.wordpress.com/2014/08/21/mixing-scala-and-java-in-a-maven-project/,官方scala-maven-plugin页面:http://davidb.github.io/scala-maven-plugin/example_java.html).
这导致了如下所示的解决方案:
<build>
<plugins>
<plugin>
<groupId>net.alchim31.maven</groupId>
<artifactId>scala-maven-plugin</artifactId>
<recompileMode>incremental</recompileMode>
<executions>
<execution>
<id>scala-compile</id>
<phase>process-resources</phase>
<goals>
<goal>add-source</goal>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>scala-test-compile</id>
<phase>process-test-resources</phase>
<goals>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
Run Code Online (Sandbox Code Playgroud)
这个解决方案运行良好 - 在process-resources阶段调用Scala编译,它编译Java和Scala代码,因此当maven编译器插件在compile阶段运行时,.class文件都已准备就绪.
问题是这个解决方案看起来并不干净.在编译阶段之前调用Scala编译过程只是为了确保它在maven编译器插件之前运行似乎是"hacky".
无论如何,Scala编译器编译Java类,所以我想我可以完全关闭默认的maven编译器插件,然后Scala编译器可以在这个compile阶段运行.虽然配置稍微长一些,但对我来说它看起来更干净:
<build>
<plugins>
<plugin>
<groupId>net.alchim31.maven</groupId>
<artifactId>scala-maven-plugin</artifactId>
<recompileMode>incremental</recompileMode>
<executions>
<execution>
<id>scala-compile</id>
<phase>compile</phase>
<goals>
<goal>add-source</goal>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>scala-test-compile</id>
<phase>test-compile</phase>
<goals>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<executions> …Run Code Online (Sandbox Code Playgroud) 我们使用Hibernate(使用JPA)和Hibernate Envers来持久化对象的历史.Web应用程序运行许多线程,其中一些是通过其他应用程序的RMI方法调用创建的,其中一些是由应用程序本身创建的,其中一些是为处理http请求而创建的(它们生成视图).
我们还使用Open Session In View模式来管理会话,因此我们的web.xml包含:
<filter>
<filter-name>openEntityManagerInViewFilter</filter-name>
<filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>openEntityManagerInViewFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Run Code Online (Sandbox Code Playgroud)
使用DAO访问数据库,所有这些都有Spring注入的EntityManagers.
@PersistenceContext
protected EntityManager em;
@PersistenceUnit
protected EntityManagerFactory emf;
Run Code Online (Sandbox Code Playgroud)
在我们决定使用Hibernate Envers之前,一切都运行良好.当任何不是视图生成线程的线程运行代码以获取旧版本的对象时,抛出异常.
@Override
public O loadByRevision(Long revision, Long id) {
@SuppressWarnings("unchecked")
O object = (O) AuditReaderFactory.get(em).createQuery().forEntitiesAtRevision(getBaseClass(), revision.intValue())
.add(AuditEntity.id().eq(id)).getSingleResult();
return object;
}
Run Code Online (Sandbox Code Playgroud)
线程"Scheduler"中的异常org.hibernate.SessionException:会话已关闭!在Org.hibernate.envers.tools.quols.QueryBuilder.toQuery(QueryBuilder)的org.hibernate.internal.AbstractSessionImpl.errorIfClosed(AbstractSessionImpl.java:129)org.hibernate.internal.SessionImpl.createQuery(SessionImpl.java:1776) .java:226)org.hibernate.envers.query.impl.AbstractAuditQuery.buildQuery(AbstractAuditQuery.java:92)org.hibernate.envers.query.impl.EntitiesAtRevisionQuery.list(EntitiesAtRevisionQuery.java:108)at org. hibernate.envers.query.impl.AbstractAuditQuery.getSingleResult(AbstractAuditQuery.java:110)(..)
当上面的代码由视图生成线程运行时,它工作正常.此外,DAO中的非envers代码适用于每个线程.例如,下面的代码段
@Override
public O load(Long id) {
final O find = em.find(getBaseClass(), id);
return find;
}
Run Code Online (Sandbox Code Playgroud)
可以通过RMI线程运行而不会出现问题.
为什么非视图线程可以在没有异常的情况下调用实体管理器上的方法,但是不能将Envers的AuditReaderFactory与该实体管理器一起使用?我认为可能在实体管理器上调用方法会创建一个临时会话但是在使用Envers时不会发生,这是真的吗?
解决该问题的最佳方法是什么(以便可以从每个线程使用AuditReaderFactory)?
我们通过JPA和Spring使用Hibernate来管理Web应用程序中的对象持久性.我们使用open-session-in-view模式为响应http请求的线程创建会话.我们还使用了一些不产生视图的线程 - 它们只是不时醒来完成工作.这会产生问题,因为默认情况下它们没有打开会话,所以它们会产生异常
org.hibernate.SessionException: Session is closed!
Run Code Online (Sandbox Code Playgroud)
要么
could not initialize proxy - no Session
Run Code Online (Sandbox Code Playgroud)
我们发现如果每个后台线程在一个注释的方法中调用它的逻辑,@Transactional就没有这种类型的例外,因为@Transactional确保线程在事务内部时有会话.
它解决了一段时间的问题,但我不认为这是一个很好的解决方案 - 使长时间运行的方法事务导致问题,因为在提交事务之前,其他线程无法看到数据库中所做的更改.
我创建了一个java-pseudocode示例来更好地说明我的问题:
public class FirstThread {
...
@Transactional
public void processQueue() {
for(element : queue){
if(elementCanBeProcessed(element)){
elementDao.saveIntoDatabase(element);
secondThread.addToQueue(element.getId());
}
}
}
private boolean elementCanBeProcessed(element){
//code that gets a few objects from database and processes them
}
}
Run Code Online (Sandbox Code Playgroud)
如果我使用所做的更改来注释整个processQueue方法@Transactional
elementDao.saveIntoDatabase(element);
Run Code Online (Sandbox Code Playgroud)
secondThread在事务提交之前不会被看到(因此直到整个队列被处理).如果我不这样做,那么线程将不会在其中进行会话,elementCanBeProcessed并且它将无法访问数据库.我也无法注释,elementCanBeProcessed因为它是这个类中的私有方法,我必须将它移动到另一个类,以便Spring代理可以工作.
是否可以将会话绑定到线程而不使整个方法具有事务性?我应该如何管理像那样的后台线程中的会话和事务?
我有一个基于 React 的应用程序,并使用 i18next 的 Trans 组件进行翻译。
假设我们有一个用户注册表单,我们想通过显示以下文本来确认已创建新帐户:
名为NAME的用户已创建。
其中NAME由用户提供并以粗体显示。
我现在的反应代码如下:
<Trans i18n={i18next} i18nKey="userCreated" values={{name: 'Tom'}}>
User with name <strong>{{name}}</strong> has been created.
</Trans>
Run Code Online (Sandbox Code Playgroud)
和以下翻译字符串
"userCreated": "User with name <1>{{name}}</1> has been created.",
Run Code Online (Sandbox Code Playgroud)
对于一个简单的情况,name: 'Tom'它工作正常并显示
名为Tom的用户已创建。
不过我想让用户在他们的名字中使用特殊字符。当我改名时Tom&Jerry我得到
Tom&Jerry已创建具有名称的用户。
经过一些研究后,我认为问题在于 i18next 和 React 都转义了它们的输入,因此名称被转义了两次。i18next.init我通过添加以下选项关闭了 i18next 转义
interpolation: {escapeValue: false},
这解决了汤姆和杰瑞的情况:
名为Tom&Jerry 的用户已创建。
但有一些输入完全破坏了它,例如设置name: 'Tom<'像这样的渲染(名称后面的所有内容都是粗体):
名为Tom 的用户已创建。
设置name: '<Tom>'给了我:
已创建具有名称的用户。
(根本没有显示名字)。我希望它像这样渲染: …