Fix conflicts in date diff
This commit is contained in:
commit
7a7b67473e
@ -9,9 +9,9 @@
|
|||||||
<version>1.0-SNAPSHOT</version>
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>com.baeldung</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>parent-modules</artifactId>
|
<artifactId>spring-boot-starter-parent</artifactId>
|
||||||
<version>1.0.0-SNAPSHOT</version>
|
<version>1.5.2.RELEASE</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
@ -21,6 +21,19 @@
|
|||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-freemarker</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.shiro</groupId>
|
||||||
|
<artifactId>shiro-spring-boot-web-starter</artifactId>
|
||||||
|
<version>${apache-shiro-core-version}</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.shiro</groupId>
|
<groupId>org.apache.shiro</groupId>
|
||||||
<artifactId>shiro-core</artifactId>
|
<artifactId>shiro-core</artifactId>
|
||||||
|
@ -0,0 +1,45 @@
|
|||||||
|
package com.baeldung;
|
||||||
|
|
||||||
|
import org.apache.shiro.realm.Realm;
|
||||||
|
import org.apache.shiro.spring.web.config.DefaultShiroFilterChainDefinition;
|
||||||
|
import org.apache.shiro.spring.web.config.ShiroFilterChainDefinition;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by smatt on 21/08/2017.
|
||||||
|
*/
|
||||||
|
@SpringBootApplication
|
||||||
|
public class ShiroSpringApplication {
|
||||||
|
|
||||||
|
private static final transient Logger log = LoggerFactory.getLogger(ShiroSpringApplication.class);
|
||||||
|
|
||||||
|
public static void main(String... args) {
|
||||||
|
SpringApplication.run(ShiroSpringApplication.class, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public Realm realm() {
|
||||||
|
return new MyCustomRealm();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public ShiroFilterChainDefinition shiroFilterChainDefinition() {
|
||||||
|
DefaultShiroFilterChainDefinition filter
|
||||||
|
= new DefaultShiroFilterChainDefinition();
|
||||||
|
|
||||||
|
filter.addPathDefinition("/secure", "authc");
|
||||||
|
filter.addPathDefinition("/**", "anon");
|
||||||
|
|
||||||
|
return filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,105 @@
|
|||||||
|
package com.baeldung.controllers;
|
||||||
|
|
||||||
|
import com.baeldung.models.UserCredentials;
|
||||||
|
import org.apache.shiro.SecurityUtils;
|
||||||
|
import org.apache.shiro.authc.AuthenticationException;
|
||||||
|
import org.apache.shiro.authc.UsernamePasswordToken;
|
||||||
|
import org.apache.shiro.subject.Subject;
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.ui.ModelMap;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMethod;
|
||||||
|
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
|
@Controller
|
||||||
|
public class ShiroSpringController {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@GetMapping("/")
|
||||||
|
public String index() {
|
||||||
|
return "index";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@RequestMapping( value = "/login", method = {RequestMethod.GET, RequestMethod.POST})
|
||||||
|
public String login(HttpServletRequest req, UserCredentials cred, RedirectAttributes attr) {
|
||||||
|
|
||||||
|
if(req.getMethod().equals(RequestMethod.GET.toString())) {
|
||||||
|
return "login";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
Subject subject = SecurityUtils.getSubject();
|
||||||
|
|
||||||
|
if(!subject.isAuthenticated()) {
|
||||||
|
UsernamePasswordToken token = new UsernamePasswordToken(
|
||||||
|
cred.getUsername(), cred.getPassword(), cred.isRememberMe());
|
||||||
|
try {
|
||||||
|
subject.login(token);
|
||||||
|
} catch (AuthenticationException ae) {
|
||||||
|
ae.printStackTrace();
|
||||||
|
attr.addFlashAttribute("error", "Invalid Credentials");
|
||||||
|
return "redirect:/login";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "redirect:/secure";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@GetMapping("/secure")
|
||||||
|
public String secure(ModelMap modelMap) {
|
||||||
|
|
||||||
|
Subject currentUser = SecurityUtils.getSubject();
|
||||||
|
String role = "", permission = "";
|
||||||
|
|
||||||
|
if(currentUser.hasRole("admin")) {
|
||||||
|
role = role + "You are an Admin";
|
||||||
|
}
|
||||||
|
else if(currentUser.hasRole("editor")) {
|
||||||
|
role = role + "You are an Editor";
|
||||||
|
}
|
||||||
|
else if(currentUser.hasRole("author")) {
|
||||||
|
role = role + "You are an Author";
|
||||||
|
}
|
||||||
|
|
||||||
|
if(currentUser.isPermitted("articles:compose")) {
|
||||||
|
permission = permission + "You can compose an article, ";
|
||||||
|
} else {
|
||||||
|
permission = permission + "You are not permitted to compose an article!, ";
|
||||||
|
}
|
||||||
|
|
||||||
|
if(currentUser.isPermitted("articles:save")) {
|
||||||
|
permission = permission + "You can save articles, ";
|
||||||
|
} else {
|
||||||
|
permission = permission + "\nYou can not save articles, ";
|
||||||
|
}
|
||||||
|
|
||||||
|
if(currentUser.isPermitted("articles:publish")) {
|
||||||
|
permission = permission + "\nYou can publish articles";
|
||||||
|
} else {
|
||||||
|
permission = permission + "\nYou can not publish articles";
|
||||||
|
}
|
||||||
|
|
||||||
|
modelMap.addAttribute("username", currentUser.getPrincipal());
|
||||||
|
modelMap.addAttribute("permission", permission);
|
||||||
|
modelMap.addAttribute("role", role);
|
||||||
|
|
||||||
|
return "secure";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@PostMapping("/logout")
|
||||||
|
public String logout() {
|
||||||
|
Subject subject = SecurityUtils.getSubject();
|
||||||
|
subject.logout();
|
||||||
|
return "redirect:/";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
package com.baeldung.models;
|
||||||
|
|
||||||
|
public class UserCredentials {
|
||||||
|
|
||||||
|
private String username;
|
||||||
|
private String password;
|
||||||
|
private boolean rememberMe = false;
|
||||||
|
|
||||||
|
public UserCredentials() {}
|
||||||
|
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUsername(String username) {
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPassword() {
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPassword(String password) {
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isRememberMe() {
|
||||||
|
return rememberMe;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRememberMe(boolean rememberMe) {
|
||||||
|
this.rememberMe = rememberMe;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "username = " + getUsername()
|
||||||
|
+ "\nrememberMe = " + isRememberMe();
|
||||||
|
}
|
||||||
|
}
|
11
apache-shiro/src/main/resources/application.properties
Normal file
11
apache-shiro/src/main/resources/application.properties
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
server.port=9000
|
||||||
|
server.servlet-path=/
|
||||||
|
server.context-path=/
|
||||||
|
|
||||||
|
#shiro-spring-boot-config
|
||||||
|
shiro.loginUrl = /login
|
||||||
|
shiro.successUrl = /secure
|
||||||
|
shiro.unauthorizedUrl = /login
|
||||||
|
|
||||||
|
#freemarker
|
||||||
|
spring.freemarker.suffix=.ftl
|
10
apache-shiro/src/main/resources/templates/index.ftl
Normal file
10
apache-shiro/src/main/resources/templates/index.ftl
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Index</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Welcome Guest!</h1>
|
||||||
|
<br>
|
||||||
|
<a href="/login">Login</a>
|
||||||
|
</body>
|
||||||
|
</html>
|
27
apache-shiro/src/main/resources/templates/login.ftl
Normal file
27
apache-shiro/src/main/resources/templates/login.ftl
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Login</title>
|
||||||
|
</head>
|
||||||
|
<body style="margin-left: 30px;">
|
||||||
|
<h3>Login</h3>
|
||||||
|
<br>
|
||||||
|
<form action="/login" method="post">
|
||||||
|
<#if (error?length > 0)??>
|
||||||
|
<p style="color:darkred;">${error}</p>
|
||||||
|
<#else>
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<label for="username">Username</label>
|
||||||
|
<br>
|
||||||
|
<input type="text" name="username">
|
||||||
|
<br><br>
|
||||||
|
<label for="password">Password</label>
|
||||||
|
<br>
|
||||||
|
<input type="password" name="password">
|
||||||
|
<br><br>
|
||||||
|
<input type="checkbox" name="rememberMe"> Remember Me
|
||||||
|
<br><br>
|
||||||
|
<input type="submit" value="Submit">
|
||||||
|
</form>
|
||||||
|
</body>
|
||||||
|
</html>
|
15
apache-shiro/src/main/resources/templates/secure.ftl
Normal file
15
apache-shiro/src/main/resources/templates/secure.ftl
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Secure</title>
|
||||||
|
</head>
|
||||||
|
<body style="margin-left: 30px;">
|
||||||
|
<h1>Welcome ${username}!</h1>
|
||||||
|
<p><strong>Role</strong>: ${role}</p>
|
||||||
|
<p><strong>Permissions</strong></p>
|
||||||
|
<p>${permission}</p>
|
||||||
|
<br>
|
||||||
|
<form role="form" action="/logout" method="POST">
|
||||||
|
<input type="Submit" value="Logout" />
|
||||||
|
</form>
|
||||||
|
</body>
|
||||||
|
</html>
|
26
core-java-concurrency/.gitignore
vendored
Normal file
26
core-java-concurrency/.gitignore
vendored
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
*.class
|
||||||
|
|
||||||
|
0.*
|
||||||
|
|
||||||
|
#folders#
|
||||||
|
/target
|
||||||
|
/neoDb*
|
||||||
|
/data
|
||||||
|
/src/main/webapp/WEB-INF/classes
|
||||||
|
*/META-INF/*
|
||||||
|
.resourceCache
|
||||||
|
|
||||||
|
# Packaged files #
|
||||||
|
*.jar
|
||||||
|
*.war
|
||||||
|
*.ear
|
||||||
|
|
||||||
|
# Files generated by integration tests
|
||||||
|
*.txt
|
||||||
|
backup-pom.xml
|
||||||
|
/bin/
|
||||||
|
/temp
|
||||||
|
|
||||||
|
#IntelliJ specific
|
||||||
|
.idea/
|
||||||
|
*.iml
|
32
core-java-concurrency/README.md
Normal file
32
core-java-concurrency/README.md
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
=========
|
||||||
|
|
||||||
|
## Core Java Concurrency Examples
|
||||||
|
|
||||||
|
### Relevant Articles:
|
||||||
|
- [Guide To CompletableFuture](http://www.baeldung.com/java-completablefuture)
|
||||||
|
- [A Guide to the Java ExecutorService](http://www.baeldung.com/java-executor-service-tutorial)
|
||||||
|
- [Introduction to Thread Pools in Java](http://www.baeldung.com/thread-pool-java-and-guava)
|
||||||
|
- [Guide to java.util.concurrent.Future](http://www.baeldung.com/java-future)
|
||||||
|
- [Guide to java.util.concurrent.BlockingQueue](http://www.baeldung.com/java-blocking-queue)
|
||||||
|
- [Guide to CountDownLatch in Java](http://www.baeldung.com/java-countdown-latch)
|
||||||
|
- [A Guide to ConcurrentMap](http://www.baeldung.com/java-concurrent-map)
|
||||||
|
- [Guide to PriorityBlockingQueue in Java](http://www.baeldung.com/java-priority-blocking-queue)
|
||||||
|
- [Avoiding the ConcurrentModificationException in Java](http://www.baeldung.com/java-concurrentmodificationexception)
|
||||||
|
- [Custom Thread Pools In Java 8 Parallel Streams](http://www.baeldung.com/java-8-parallel-streams-custom-threadpool)
|
||||||
|
- [Guide to java.util.concurrent.Locks](http://www.baeldung.com/java-concurrent-locks)
|
||||||
|
- [An Introduction to ThreadLocal in Java](http://www.baeldung.com/java-threadlocal)
|
||||||
|
- [Guide to DelayQueue](http://www.baeldung.com/java-delay-queue)
|
||||||
|
- [A Guide to Java SynchronousQueue](http://www.baeldung.com/java-synchronous-queue)
|
||||||
|
- [Guide to the Java TransferQueue](http://www.baeldung.com/java-transfer-queue)
|
||||||
|
- [Guide to the ConcurrentSkipListMap](http://www.baeldung.com/java-concurrent-skip-list-map)
|
||||||
|
- [Difference Between Wait and Sleep in Java](http://www.baeldung.com/java-wait-and-sleep)
|
||||||
|
- [LongAdder and LongAccumulator in Java](http://www.baeldung.com/java-longadder-and-longaccumulator)
|
||||||
|
- [The Dining Philosophers Problem in Java](http://www.baeldung.com/java-dining-philoshophers)
|
||||||
|
- [Guide to CopyOnWriteArrayList](http://www.baeldung.com/java-copy-on-write-arraylist)
|
||||||
|
- [Guide to the Java Phaser](http://www.baeldung.com/java-phaser)
|
||||||
|
- [Guide to Synchronized Keyword in Java](http://www.baeldung.com/java-synchronized)
|
||||||
|
- [An Introduction to Atomic Variables in Java](http://www.baeldung.com/java-atomic-variables)
|
||||||
|
- [CyclicBarrier in Java](http://www.baeldung.com/java-cyclic-barrier)
|
||||||
|
- [Guide to Volatile Keyword in Java](http://www.baeldung.com/java-volatile)
|
||||||
|
- [Overview of the java.util.concurrent](http://www.baeldung.com/java-util-concurrent)
|
||||||
|
- [Semaphores in Java](http://www.baeldung.com/java-semaphore)
|
237
core-java-concurrency/pom.xml
Normal file
237
core-java-concurrency/pom.xml
Normal file
@ -0,0 +1,237 @@
|
|||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<groupId>com.baeldung</groupId>
|
||||||
|
<artifactId>core-java-concurrency</artifactId>
|
||||||
|
<version>0.1.0-SNAPSHOT</version>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
<name>core-java-concurrency</name>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>com.baeldung</groupId>
|
||||||
|
<artifactId>parent-modules</artifactId>
|
||||||
|
<version>1.0.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
|
||||||
|
<!-- utils -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.guava</groupId>
|
||||||
|
<artifactId>guava</artifactId>
|
||||||
|
<version>${guava.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-collections4</artifactId>
|
||||||
|
<version>${commons-collections4.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>commons-io</groupId>
|
||||||
|
<artifactId>commons-io</artifactId>
|
||||||
|
<version>${commons-io.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-lang3</artifactId>
|
||||||
|
<version>${commons-lang3.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-math3</artifactId>
|
||||||
|
<version>${commons-math3.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- test scoped -->
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.assertj</groupId>
|
||||||
|
<artifactId>assertj-core</artifactId>
|
||||||
|
<version>${assertj.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.jayway.awaitility</groupId>
|
||||||
|
<artifactId>awaitility</artifactId>
|
||||||
|
<version>${avaitility.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<finalName>core-java-concurrency</finalName>
|
||||||
|
<resources>
|
||||||
|
<resource>
|
||||||
|
<directory>src/main/resources</directory>
|
||||||
|
<filtering>true</filtering>
|
||||||
|
</resource>
|
||||||
|
</resources>
|
||||||
|
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-dependency-plugin</artifactId>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>copy-dependencies</id>
|
||||||
|
<phase>prepare-package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>copy-dependencies</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<outputDirectory>${project.build.directory}/libs</outputDirectory>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-jar-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<archive>
|
||||||
|
<manifest>
|
||||||
|
<addClasspath>true</addClasspath>
|
||||||
|
<classpathPrefix>libs/</classpathPrefix>
|
||||||
|
<mainClass>org.baeldung.executable.ExecutableMavenJar</mainClass>
|
||||||
|
</manifest>
|
||||||
|
</archive>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-assembly-plugin</artifactId>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<phase>package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>single</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<archiveBaseDirectory>${project.basedir}</archiveBaseDirectory>
|
||||||
|
<archive>
|
||||||
|
<manifest>
|
||||||
|
<mainClass>org.baeldung.executable.ExecutableMavenJar</mainClass>
|
||||||
|
</manifest>
|
||||||
|
</archive>
|
||||||
|
<descriptorRefs>
|
||||||
|
<descriptorRef>jar-with-dependencies</descriptorRef>
|
||||||
|
</descriptorRefs>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-shade-plugin</artifactId>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<goals>
|
||||||
|
<goal>shade</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<shadedArtifactAttached>true</shadedArtifactAttached>
|
||||||
|
<transformers>
|
||||||
|
<transformer
|
||||||
|
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
|
||||||
|
<mainClass>org.baeldung.executable.ExecutableMavenJar</mainClass>
|
||||||
|
</transformer>
|
||||||
|
</transformers>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>com.jolira</groupId>
|
||||||
|
<artifactId>onejar-maven-plugin</artifactId>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<configuration>
|
||||||
|
<mainClass>org.baeldung.executable.ExecutableMavenJar</mainClass>
|
||||||
|
<attachToBuild>true</attachToBuild>
|
||||||
|
<filename>${project.build.finalName}-onejar.${project.packaging}</filename>
|
||||||
|
</configuration>
|
||||||
|
<goals>
|
||||||
|
<goal>one-jar</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<goals>
|
||||||
|
<goal>repackage</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<classifier>spring-boot</classifier>
|
||||||
|
<mainClass>org.baeldung.executable.ExecutableMavenJar</mainClass>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
|
||||||
|
</build>
|
||||||
|
|
||||||
|
<profiles>
|
||||||
|
<profile>
|
||||||
|
<id>integration</id>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<phase>integration-test</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>test</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<excludes>
|
||||||
|
<exclude>**/*ManualTest.java</exclude>
|
||||||
|
</excludes>
|
||||||
|
<includes>
|
||||||
|
<include>**/*IntegrationTest.java</include>
|
||||||
|
</includes>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
<configuration>
|
||||||
|
<systemPropertyVariables>
|
||||||
|
<test.mime>json</test.mime>
|
||||||
|
</systemPropertyVariables>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</profile>
|
||||||
|
</profiles>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
|
||||||
|
<!-- util -->
|
||||||
|
<guava.version>21.0</guava.version>
|
||||||
|
<commons-lang3.version>3.5</commons-lang3.version>
|
||||||
|
<commons-math3.version>3.6.1</commons-math3.version>
|
||||||
|
<commons-io.version>2.5</commons-io.version>
|
||||||
|
<commons-collections4.version>4.1</commons-collections4.version>
|
||||||
|
<collections-generic.version>4.01</collections-generic.version>
|
||||||
|
|
||||||
|
<!-- testing -->
|
||||||
|
<assertj.version>3.6.1</assertj.version>
|
||||||
|
<avaitility.version>1.7.0</avaitility.version>
|
||||||
|
|
||||||
|
</properties>
|
||||||
|
</project>
|
@ -3,11 +3,11 @@ package com.baeldung.concurrent.atomic;
|
|||||||
public class SafeCounterWithLock {
|
public class SafeCounterWithLock {
|
||||||
private volatile int counter;
|
private volatile int counter;
|
||||||
|
|
||||||
public int getValue() {
|
int getValue() {
|
||||||
return counter;
|
return counter;
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void increment() {
|
synchronized void increment() {
|
||||||
counter++;
|
counter++;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -5,11 +5,11 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||||||
public class SafeCounterWithoutLock {
|
public class SafeCounterWithoutLock {
|
||||||
private final AtomicInteger counter = new AtomicInteger(0);
|
private final AtomicInteger counter = new AtomicInteger(0);
|
||||||
|
|
||||||
public int getValue() {
|
int getValue() {
|
||||||
return counter.get();
|
return counter.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void increment() {
|
void increment() {
|
||||||
while(true) {
|
while(true) {
|
||||||
int existingValue = getValue();
|
int existingValue = getValue();
|
||||||
int newValue = existingValue + 1;
|
int newValue = existingValue + 1;
|
@ -1,13 +1,13 @@
|
|||||||
package com.baeldung.concurrent.atomic;
|
package com.baeldung.concurrent.atomic;
|
||||||
|
|
||||||
public class UnsafeCounter {
|
public class UnsafeCounter {
|
||||||
int counter;
|
private int counter;
|
||||||
|
|
||||||
public int getValue() {
|
int getValue() {
|
||||||
return counter;
|
return counter;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void increment() {
|
void increment() {
|
||||||
counter++;
|
counter++;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -4,14 +4,14 @@ package com.baeldung.threadlocal;
|
|||||||
public class Context {
|
public class Context {
|
||||||
private final String userName;
|
private final String userName;
|
||||||
|
|
||||||
public Context(String userName) {
|
Context(String userName) {
|
||||||
this.userName = userName;
|
this.userName = userName;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Context{" +
|
return "Context{" +
|
||||||
"userNameSecret='" + userName + '\'' +
|
"userNameSecret='" + userName + '\'' +
|
||||||
'}';
|
'}';
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -5,11 +5,11 @@ import java.util.Map;
|
|||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
public class SharedMapWithUserContext implements Runnable {
|
public class SharedMapWithUserContext implements Runnable {
|
||||||
public final static Map<Integer, Context> userContextPerUserId = new ConcurrentHashMap<>();
|
final static Map<Integer, Context> userContextPerUserId = new ConcurrentHashMap<>();
|
||||||
private final Integer userId;
|
private final Integer userId;
|
||||||
private UserRepository userRepository = new UserRepository();
|
private UserRepository userRepository = new UserRepository();
|
||||||
|
|
||||||
public SharedMapWithUserContext(Integer userId) {
|
SharedMapWithUserContext(Integer userId) {
|
||||||
this.userId = userId;
|
this.userId = userId;
|
||||||
}
|
}
|
||||||
|
|
@ -10,7 +10,7 @@ public class ThreadLocalWithUserContext implements Runnable {
|
|||||||
private final Integer userId;
|
private final Integer userId;
|
||||||
private UserRepository userRepository = new UserRepository();
|
private UserRepository userRepository = new UserRepository();
|
||||||
|
|
||||||
public ThreadLocalWithUserContext(Integer userId) {
|
ThreadLocalWithUserContext(Integer userId) {
|
||||||
this.userId = userId;
|
this.userId = userId;
|
||||||
}
|
}
|
||||||
|
|
@ -4,7 +4,7 @@ import java.util.UUID;
|
|||||||
|
|
||||||
|
|
||||||
public class UserRepository {
|
public class UserRepository {
|
||||||
public String getUserNameForUserId(Integer userId) {
|
String getUserNameForUserId(Integer userId) {
|
||||||
return UUID.randomUUID().toString();
|
return UUID.randomUUID().toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -2,19 +2,21 @@ package com.baeldung.threadpool;
|
|||||||
|
|
||||||
import java.util.concurrent.ForkJoinTask;
|
import java.util.concurrent.ForkJoinTask;
|
||||||
import java.util.concurrent.RecursiveTask;
|
import java.util.concurrent.RecursiveTask;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
public class CountingTask extends RecursiveTask<Integer> {
|
public class CountingTask extends RecursiveTask<Integer> {
|
||||||
|
|
||||||
private final TreeNode node;
|
private final TreeNode node;
|
||||||
|
|
||||||
public CountingTask(TreeNode node) {
|
CountingTask(TreeNode node) {
|
||||||
this.node = node;
|
this.node = node;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Integer compute() {
|
protected Integer compute() {
|
||||||
return node.value + node.children.stream().map(childNode -> new CountingTask(childNode).fork()).collect(Collectors.summingInt(ForkJoinTask::join));
|
return node.getValue() + node.getChildren().stream()
|
||||||
|
.map(childNode -> new CountingTask(childNode).fork())
|
||||||
|
.mapToInt(ForkJoinTask::join)
|
||||||
|
.sum();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
package com.baeldung.threadpool;
|
||||||
|
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class TreeNode {
|
||||||
|
|
||||||
|
private int value;
|
||||||
|
|
||||||
|
private Set<TreeNode> children;
|
||||||
|
|
||||||
|
TreeNode(int value, TreeNode... children) {
|
||||||
|
this.value = value;
|
||||||
|
this.children = Sets.newHashSet(children);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<TreeNode> getChildren() {
|
||||||
|
return children;
|
||||||
|
}
|
||||||
|
}
|
@ -11,10 +11,10 @@ public class Consumer implements Runnable {
|
|||||||
|
|
||||||
private final TransferQueue<String> transferQueue;
|
private final TransferQueue<String> transferQueue;
|
||||||
private final String name;
|
private final String name;
|
||||||
private final int numberOfMessagesToConsume;
|
final int numberOfMessagesToConsume;
|
||||||
public final AtomicInteger numberOfConsumedMessages = new AtomicInteger();
|
final AtomicInteger numberOfConsumedMessages = new AtomicInteger();
|
||||||
|
|
||||||
public Consumer(TransferQueue<String> transferQueue, String name, int numberOfMessagesToConsume) {
|
Consumer(TransferQueue<String> transferQueue, String name, int numberOfMessagesToConsume) {
|
||||||
this.transferQueue = transferQueue;
|
this.transferQueue = transferQueue;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.numberOfMessagesToConsume = numberOfMessagesToConsume;
|
this.numberOfMessagesToConsume = numberOfMessagesToConsume;
|
@ -12,10 +12,10 @@ public class Producer implements Runnable {
|
|||||||
|
|
||||||
private final TransferQueue<String> transferQueue;
|
private final TransferQueue<String> transferQueue;
|
||||||
private final String name;
|
private final String name;
|
||||||
private final Integer numberOfMessagesToProduce;
|
final Integer numberOfMessagesToProduce;
|
||||||
public final AtomicInteger numberOfProducedMessages = new AtomicInteger();
|
final AtomicInteger numberOfProducedMessages = new AtomicInteger();
|
||||||
|
|
||||||
public Producer(TransferQueue<String> transferQueue, String name, Integer numberOfMessagesToProduce) {
|
Producer(TransferQueue<String> transferQueue, String name, Integer numberOfMessagesToProduce) {
|
||||||
this.transferQueue = transferQueue;
|
this.transferQueue = transferQueue;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.numberOfMessagesToProduce = numberOfMessagesToProduce;
|
this.numberOfMessagesToProduce = numberOfMessagesToProduce;
|
9
core-java-concurrency/src/main/java/log4j.properties
Normal file
9
core-java-concurrency/src/main/java/log4j.properties
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# Set root logger level to DEBUG and its only appender to A1.
|
||||||
|
log4j.rootLogger=DEBUG, A1
|
||||||
|
|
||||||
|
# A1 is set to be a ConsoleAppender.
|
||||||
|
log4j.appender.A1=org.apache.log4j.ConsoleAppender
|
||||||
|
|
||||||
|
# A1 uses PatternLayout.
|
||||||
|
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
|
||||||
|
log4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n
|
19
core-java-concurrency/src/main/resources/logback.xml
Normal file
19
core-java-concurrency/src/main/resources/logback.xml
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<configuration>
|
||||||
|
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||||
|
<encoder>
|
||||||
|
<pattern>web - %date [%thread] %-5level %logger{36} - %message%n
|
||||||
|
</pattern>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<logger name="org.springframework" level="WARN" />
|
||||||
|
<logger name="org.springframework.transaction" level="WARN" />
|
||||||
|
|
||||||
|
<!-- in order to debug some marshalling issues, this needs to be TRACE -->
|
||||||
|
<logger name="org.springframework.web.servlet.mvc" level="WARN" />
|
||||||
|
|
||||||
|
<root level="INFO">
|
||||||
|
<appender-ref ref="STDOUT" />
|
||||||
|
</root>
|
||||||
|
</configuration>
|
@ -4,7 +4,11 @@ import org.junit.Test;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.CancellationException;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.Future;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
@ -18,7 +18,9 @@ public class CountdownLatchExampleIntegrationTest {
|
|||||||
// Given
|
// Given
|
||||||
List<String> outputScraper = Collections.synchronizedList(new ArrayList<>());
|
List<String> outputScraper = Collections.synchronizedList(new ArrayList<>());
|
||||||
CountDownLatch countDownLatch = new CountDownLatch(5);
|
CountDownLatch countDownLatch = new CountDownLatch(5);
|
||||||
List<Thread> workers = Stream.generate(() -> new Thread(new Worker(outputScraper, countDownLatch))).limit(5).collect(toList());
|
List<Thread> workers = Stream.generate(() -> new Thread(new Worker(outputScraper, countDownLatch)))
|
||||||
|
.limit(5)
|
||||||
|
.collect(toList());
|
||||||
|
|
||||||
// When
|
// When
|
||||||
workers.forEach(Thread::start);
|
workers.forEach(Thread::start);
|
||||||
@ -26,7 +28,6 @@ public class CountdownLatchExampleIntegrationTest {
|
|||||||
outputScraper.add("Latch released");
|
outputScraper.add("Latch released");
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
outputScraper.forEach(Object::toString);
|
|
||||||
assertThat(outputScraper).containsExactly("Counted down", "Counted down", "Counted down", "Counted down", "Counted down", "Latch released");
|
assertThat(outputScraper).containsExactly("Counted down", "Counted down", "Counted down", "Counted down", "Counted down", "Latch released");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,7 +36,9 @@ public class CountdownLatchExampleIntegrationTest {
|
|||||||
// Given
|
// Given
|
||||||
List<String> outputScraper = Collections.synchronizedList(new ArrayList<>());
|
List<String> outputScraper = Collections.synchronizedList(new ArrayList<>());
|
||||||
CountDownLatch countDownLatch = new CountDownLatch(5);
|
CountDownLatch countDownLatch = new CountDownLatch(5);
|
||||||
List<Thread> workers = Stream.generate(() -> new Thread(new BrokenWorker(outputScraper, countDownLatch))).limit(5).collect(toList());
|
List<Thread> workers = Stream.generate(() -> new Thread(new BrokenWorker(outputScraper, countDownLatch)))
|
||||||
|
.limit(5)
|
||||||
|
.collect(toList());
|
||||||
|
|
||||||
// When
|
// When
|
||||||
workers.forEach(Thread::start);
|
workers.forEach(Thread::start);
|
||||||
@ -63,7 +66,6 @@ public class CountdownLatchExampleIntegrationTest {
|
|||||||
outputScraper.add("Workers complete");
|
outputScraper.add("Workers complete");
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
outputScraper.forEach(Object::toString);
|
|
||||||
assertThat(outputScraper).containsExactly("Workers ready", "Counted down", "Counted down", "Counted down", "Counted down", "Counted down", "Workers complete");
|
assertThat(outputScraper).containsExactly("Workers ready", "Counted down", "Counted down", "Counted down", "Counted down", "Counted down", "Workers complete");
|
||||||
}
|
}
|
||||||
|
|
@ -22,7 +22,6 @@ public class SquareCalculatorIntegrationTest {
|
|||||||
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(SquareCalculatorIntegrationTest.class);
|
private static final Logger LOG = LoggerFactory.getLogger(SquareCalculatorIntegrationTest.class);
|
||||||
|
|
||||||
|
|
||||||
@Rule
|
@Rule
|
||||||
public TestName name = new TestName();
|
public TestName name = new TestName();
|
||||||
|
|
@ -49,9 +49,7 @@ public class SynchronizedHashMapWithRWLockManualTest {
|
|||||||
|
|
||||||
private void executeReaderThreads(SynchronizedHashMapWithRWLock object, int threadCount, ExecutorService service) {
|
private void executeReaderThreads(SynchronizedHashMapWithRWLock object, int threadCount, ExecutorService service) {
|
||||||
for (int i = 0; i < threadCount; i++)
|
for (int i = 0; i < threadCount; i++)
|
||||||
service.execute(() -> {
|
service.execute(() -> object.get("key" + threadCount));
|
||||||
object.get("key" + threadCount);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -12,7 +12,7 @@ import static org.junit.Assert.assertNull;
|
|||||||
|
|
||||||
public class ConcurrentMapNullKeyValueManualTest {
|
public class ConcurrentMapNullKeyValueManualTest {
|
||||||
|
|
||||||
ConcurrentMap<String, Object> concurrentMap;
|
private ConcurrentMap<String, Object> concurrentMap;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() {
|
public void setup() {
|
@ -1,27 +1,31 @@
|
|||||||
package com.baeldung.java.concurrentmap;
|
package com.baeldung.java.concurrentmap;
|
||||||
|
|
||||||
import org.junit.Test;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Hashtable;
|
import java.util.Hashtable;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import org.junit.Test;
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
|
|
||||||
public class ConcurrentMapPerformanceManualTest {
|
public class ConcurrentMapPerformanceManualTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void givenMaps_whenGetPut500KTimes_thenConcurrentMapFaster() throws Exception {
|
public void givenMaps_whenGetPut500KTimes_thenConcurrentMapFaster() throws Exception {
|
||||||
Map<String, Object> hashtable = new Hashtable<>();
|
final Map<String, Object> hashtable = new Hashtable<>();
|
||||||
Map<String, Object> synchronizedHashMap = Collections.synchronizedMap(new HashMap<>());
|
final Map<String, Object> synchronizedHashMap = Collections.synchronizedMap(new HashMap<>());
|
||||||
Map<String, Object> concurrentHashMap = new ConcurrentHashMap<>();
|
final Map<String, Object> concurrentHashMap = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
long hashtableAvgRuntime = timeElapseForGetPut(hashtable);
|
final long hashtableAvgRuntime = timeElapseForGetPut(hashtable);
|
||||||
long syncHashMapAvgRuntime = timeElapseForGetPut(synchronizedHashMap);
|
final long syncHashMapAvgRuntime = timeElapseForGetPut(synchronizedHashMap);
|
||||||
long concurrentHashMapAvgRuntime = timeElapseForGetPut(concurrentHashMap);
|
final long concurrentHashMapAvgRuntime = timeElapseForGetPut(concurrentHashMap);
|
||||||
|
|
||||||
System.out.println(String.format("Hashtable: %s, syncHashMap: %s, ConcurrentHashMap: %s", hashtableAvgRuntime, syncHashMapAvgRuntime, concurrentHashMapAvgRuntime));
|
System.out.println(String.format("Hashtable: %s, syncHashMap: %s, ConcurrentHashMap: %s", hashtableAvgRuntime, syncHashMapAvgRuntime, concurrentHashMapAvgRuntime));
|
||||||
|
|
||||||
@ -31,13 +35,13 @@ public class ConcurrentMapPerformanceManualTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private long timeElapseForGetPut(Map<String, Object> map) throws InterruptedException {
|
private long timeElapseForGetPut(Map<String, Object> map) throws InterruptedException {
|
||||||
ExecutorService executorService = Executors.newFixedThreadPool(4);
|
final ExecutorService executorService = Executors.newFixedThreadPool(4);
|
||||||
long startTime = System.nanoTime();
|
final long startTime = System.nanoTime();
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
executorService.execute(() -> {
|
executorService.execute(() -> {
|
||||||
for (int j = 0; j < 500_000; j++) {
|
for (int j = 0; j < 500_000; j++) {
|
||||||
int value = ThreadLocalRandom.current().nextInt(10000);
|
final int value = ThreadLocalRandom.current().nextInt(10000);
|
||||||
String key = String.valueOf(value);
|
final String key = String.valueOf(value);
|
||||||
map.put(key, value);
|
map.put(key, value);
|
||||||
map.get(key);
|
map.get(key);
|
||||||
}
|
}
|
||||||
@ -56,11 +60,11 @@ public class ConcurrentMapPerformanceManualTest {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int executeTimes = 5000;
|
final int executeTimes = 5000;
|
||||||
|
|
||||||
Map<SameHash, Integer> mapOfSameHash = new ConcurrentHashMap<>();
|
final Map<SameHash, Integer> mapOfSameHash = new ConcurrentHashMap<>();
|
||||||
ExecutorService executorService = Executors.newFixedThreadPool(2);
|
ExecutorService executorService = Executors.newFixedThreadPool(2);
|
||||||
long sameHashStartTime = System.currentTimeMillis();
|
final long sameHashStartTime = System.currentTimeMillis();
|
||||||
for (int i = 0; i < 2; i++) {
|
for (int i = 0; i < 2; i++) {
|
||||||
executorService.execute(() -> {
|
executorService.execute(() -> {
|
||||||
for (int j = 0; j < executeTimes; j++) {
|
for (int j = 0; j < executeTimes; j++) {
|
||||||
@ -71,10 +75,10 @@ public class ConcurrentMapPerformanceManualTest {
|
|||||||
executorService.shutdown();
|
executorService.shutdown();
|
||||||
executorService.awaitTermination(5, TimeUnit.SECONDS);
|
executorService.awaitTermination(5, TimeUnit.SECONDS);
|
||||||
|
|
||||||
long mapOfSameHashDuration = System.currentTimeMillis() - sameHashStartTime;
|
final long mapOfSameHashDuration = System.currentTimeMillis() - sameHashStartTime;
|
||||||
Map<Object, Integer> mapOfDefaultHash = new ConcurrentHashMap<>();
|
final Map<Object, Integer> mapOfDefaultHash = new ConcurrentHashMap<>();
|
||||||
executorService = Executors.newFixedThreadPool(2);
|
executorService = Executors.newFixedThreadPool(2);
|
||||||
long defaultHashStartTime = System.currentTimeMillis();
|
final long defaultHashStartTime = System.currentTimeMillis();
|
||||||
for (int i = 0; i < 2; i++) {
|
for (int i = 0; i < 2; i++) {
|
||||||
executorService.execute(() -> {
|
executorService.execute(() -> {
|
||||||
for (int j = 0; j < executeTimes; j++) {
|
for (int j = 0; j < executeTimes; j++) {
|
||||||
@ -85,11 +89,11 @@ public class ConcurrentMapPerformanceManualTest {
|
|||||||
executorService.shutdown();
|
executorService.shutdown();
|
||||||
executorService.awaitTermination(5, TimeUnit.SECONDS);
|
executorService.awaitTermination(5, TimeUnit.SECONDS);
|
||||||
|
|
||||||
long mapOfDefaultHashDuration = System.currentTimeMillis() - defaultHashStartTime;
|
final long mapOfDefaultHashDuration = System.currentTimeMillis() - defaultHashStartTime;
|
||||||
assertEquals(executeTimes * 2, mapOfDefaultHash.size());
|
assertEquals(executeTimes * 2, mapOfDefaultHash.size());
|
||||||
assertEquals(executeTimes * 2, mapOfSameHash.size());
|
assertEquals(executeTimes * 2, mapOfSameHash.size());
|
||||||
System.out.println(String.format("same-hash: %s, default-hash: %s", mapOfSameHashDuration, mapOfDefaultHashDuration));
|
System.out.println(String.format("same-hash: %s, default-hash: %s", mapOfSameHashDuration, mapOfDefaultHashDuration));
|
||||||
assertTrue("same hashCode() should greatly degrade performance", mapOfSameHashDuration > mapOfDefaultHashDuration * 10);
|
assertTrue("same hashCode() should greatly degrade performance", mapOfSameHashDuration > (mapOfDefaultHashDuration * 10));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -18,7 +18,7 @@ public class ConcurrentNavigableMapManualTest {
|
|||||||
public void givenSkipListMap_whenAccessInMultiThreads_thenOrderingStable() throws InterruptedException {
|
public void givenSkipListMap_whenAccessInMultiThreads_thenOrderingStable() throws InterruptedException {
|
||||||
NavigableMap<Integer, String> skipListMap = new ConcurrentSkipListMap<>();
|
NavigableMap<Integer, String> skipListMap = new ConcurrentSkipListMap<>();
|
||||||
|
|
||||||
updateMapConcurrently(skipListMap, 4);
|
updateMapConcurrently(skipListMap);
|
||||||
|
|
||||||
Iterator<Integer> skipListIter = skipListMap.keySet().iterator();
|
Iterator<Integer> skipListIter = skipListMap.keySet().iterator();
|
||||||
int previous = skipListIter.next();
|
int previous = skipListIter.next();
|
||||||
@ -28,9 +28,9 @@ public class ConcurrentNavigableMapManualTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateMapConcurrently(NavigableMap<Integer, String> navigableMap, int concurrencyLevel) throws InterruptedException {
|
private void updateMapConcurrently(NavigableMap<Integer, String> navigableMap) throws InterruptedException {
|
||||||
ExecutorService executorService = Executors.newFixedThreadPool(concurrencyLevel);
|
ExecutorService executorService = Executors.newFixedThreadPool(4);
|
||||||
for (int i = 0; i < concurrencyLevel; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
executorService.execute(() -> {
|
executorService.execute(() -> {
|
||||||
ThreadLocalRandom random = ThreadLocalRandom.current();
|
ThreadLocalRandom random = ThreadLocalRandom.current();
|
||||||
for (int j = 0; j < 10000; j++) {
|
for (int j = 0; j < 10000; j++) {
|
||||||
@ -45,26 +45,26 @@ public class ConcurrentNavigableMapManualTest {
|
|||||||
@Test
|
@Test
|
||||||
public void givenSkipListMap_whenNavConcurrently_thenCountCorrect() throws InterruptedException {
|
public void givenSkipListMap_whenNavConcurrently_thenCountCorrect() throws InterruptedException {
|
||||||
NavigableMap<Integer, Integer> skipListMap = new ConcurrentSkipListMap<>();
|
NavigableMap<Integer, Integer> skipListMap = new ConcurrentSkipListMap<>();
|
||||||
int count = countMapElementByPollingFirstEntry(skipListMap, 10000, 4);
|
int count = countMapElementByPollingFirstEntry(skipListMap);
|
||||||
assertEquals(10000 * 4, count);
|
assertEquals(10000 * 4, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void givenTreeMap_whenNavConcurrently_thenCountError() throws InterruptedException {
|
public void givenTreeMap_whenNavConcurrently_thenCountError() throws InterruptedException {
|
||||||
NavigableMap<Integer, Integer> treeMap = new TreeMap<>();
|
NavigableMap<Integer, Integer> treeMap = new TreeMap<>();
|
||||||
int count = countMapElementByPollingFirstEntry(treeMap, 10000, 4);
|
int count = countMapElementByPollingFirstEntry(treeMap);
|
||||||
assertNotEquals(10000 * 4, count);
|
assertNotEquals(10000 * 4, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
private int countMapElementByPollingFirstEntry(NavigableMap<Integer, Integer> navigableMap, int elementCount, int concurrencyLevel) throws InterruptedException {
|
private int countMapElementByPollingFirstEntry(NavigableMap<Integer, Integer> navigableMap) throws InterruptedException {
|
||||||
for (int i = 0; i < elementCount * concurrencyLevel; i++) {
|
for (int i = 0; i < 10000 * 4; i++) {
|
||||||
navigableMap.put(i, i);
|
navigableMap.put(i, i);
|
||||||
}
|
}
|
||||||
AtomicInteger counter = new AtomicInteger(0);
|
AtomicInteger counter = new AtomicInteger(0);
|
||||||
ExecutorService executorService = Executors.newFixedThreadPool(concurrencyLevel);
|
ExecutorService executorService = Executors.newFixedThreadPool(4);
|
||||||
for (int j = 0; j < concurrencyLevel; j++) {
|
for (int j = 0; j < 4; j++) {
|
||||||
executorService.execute(() -> {
|
executorService.execute(() -> {
|
||||||
for (int i = 0; i < elementCount; i++) {
|
for (int i = 0; i < 10000; i++) {
|
||||||
if (navigableMap.pollFirstEntry() != null) {
|
if (navigableMap.pollFirstEntry() != null) {
|
||||||
counter.incrementAndGet();
|
counter.incrementAndGet();
|
||||||
}
|
}
|
@ -2,7 +2,6 @@ package com.baeldung.java.concurrentmodification;
|
|||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.ConcurrentModificationException;
|
import java.util.ConcurrentModificationException;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
@ -28,9 +27,9 @@ public class ConcurrentModificationUnitTest {
|
|||||||
|
|
||||||
List<Integer> integers = newArrayList(1, 2, 3);
|
List<Integer> integers = newArrayList(1, 2, 3);
|
||||||
|
|
||||||
for (Iterator<Integer> iterator = integers.iterator(); iterator.hasNext();) {
|
for (Iterator<Integer> iterator = integers.iterator(); iterator.hasNext(); ) {
|
||||||
Integer integer = iterator.next();
|
Integer integer = iterator.next();
|
||||||
if(integer == 2) {
|
if (integer == 2) {
|
||||||
iterator.remove();
|
iterator.remove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -45,7 +44,7 @@ public class ConcurrentModificationUnitTest {
|
|||||||
List<Integer> toRemove = newArrayList();
|
List<Integer> toRemove = newArrayList();
|
||||||
|
|
||||||
for (Integer integer : integers) {
|
for (Integer integer : integers) {
|
||||||
if(integer == 2) {
|
if (integer == 2) {
|
||||||
toRemove.add(integer);
|
toRemove.add(integer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -69,10 +68,10 @@ public class ConcurrentModificationUnitTest {
|
|||||||
Collection<Integer> integers = newArrayList(1, 2, 3);
|
Collection<Integer> integers = newArrayList(1, 2, 3);
|
||||||
|
|
||||||
List<String> collected = integers
|
List<String> collected = integers
|
||||||
.stream()
|
.stream()
|
||||||
.filter(i -> i != 2)
|
.filter(i -> i != 2)
|
||||||
.map(Object::toString)
|
.map(Object::toString)
|
||||||
.collect(toList());
|
.collect(toList());
|
||||||
|
|
||||||
assertThat(collected).containsExactly("1", "3");
|
assertThat(collected).containsExactly("1", "3");
|
||||||
}
|
}
|
@ -72,7 +72,7 @@ public class Java8ExecutorServiceIntegrationTest {
|
|||||||
|
|
||||||
assertTrue(threadPoolExecutor.isShutdown());
|
assertTrue(threadPoolExecutor.isShutdown());
|
||||||
assertFalse(notExecutedTasks.isEmpty());
|
assertFalse(notExecutedTasks.isEmpty());
|
||||||
assertTrue(notExecutedTasks.size() > 0 && notExecutedTasks.size() < 98);
|
assertTrue(notExecutedTasks.size() < 98);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Runnable> smartShutdown(ExecutorService executorService) {
|
private List<Runnable> smartShutdown(ExecutorService executorService) {
|
@ -23,7 +23,10 @@ public class ThreadPoolInParallelStreamIntegrationTest {
|
|||||||
List<Long> aList = LongStream.rangeClosed(firstNum, lastNum).boxed().collect(Collectors.toList());
|
List<Long> aList = LongStream.rangeClosed(firstNum, lastNum).boxed().collect(Collectors.toList());
|
||||||
|
|
||||||
ForkJoinPool customThreadPool = new ForkJoinPool(4);
|
ForkJoinPool customThreadPool = new ForkJoinPool(4);
|
||||||
long actualTotal = customThreadPool.submit(() -> aList.parallelStream().reduce(0L, Long::sum)).get();
|
long actualTotal = customThreadPool
|
||||||
|
.submit(() -> aList.parallelStream()
|
||||||
|
.reduce(0L, Long::sum))
|
||||||
|
.get();
|
||||||
|
|
||||||
assertEquals((lastNum + firstNum) * lastNum / 2, actualTotal);
|
assertEquals((lastNum + firstNum) * lastNum / 2, actualTotal);
|
||||||
}
|
}
|
13
core-java-concurrency/src/test/resources/.gitignore
vendored
Normal file
13
core-java-concurrency/src/test/resources/.gitignore
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
*.class
|
||||||
|
|
||||||
|
#folders#
|
||||||
|
/target
|
||||||
|
/neoDb*
|
||||||
|
/data
|
||||||
|
/src/main/webapp/WEB-INF/classes
|
||||||
|
*/META-INF/*
|
||||||
|
|
||||||
|
# Packaged files #
|
||||||
|
*.jar
|
||||||
|
*.war
|
||||||
|
*.ear
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user