ConcurrentHashMap中putIfAbsent实现并发安全的添加

User.java

package org.example.chm3;

/**
 * @author jianan
 * @date 2021/7/6 15:44:29
 */
public class User {
	private String username;
	private int age;

	public User(String username, int age) {
		this.username = username;
		this.age = age;
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}
}

UserService.java

package org.example.chm3;

import com.google.common.collect.Maps;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


import java.util.Map;

/**
 * @author jianan
 * @date 2021/7/6 15:44:10
 */
public class UserService {
	private static Logger logger = LoggerFactory.getLogger(UserService.class);
	private static Map userMap = Maps.newConcurrentMap();

    // 不安全的写法
	public static boolean registerUnsafe(User user) {
		if (userMap.containsKey(user.getUsername())) {
			logger.info("用户已存在");
			return false;
		} else {
			userMap.put(user.getUsername(), user);
			logger.info("用户注册成功, {},{}", user.getUsername(), user.getAge());
			return true;
		}
	}

    // 安全的写法
	public static boolean registerSafe(User user) {
		User user1 = userMap.putIfAbsent(user.getUsername(), user);
		if (user1 != null){
			logger.info("用户已存在");
			return false;
		} else{
			logger.info("用户注册成功, {},{}", user.getUsername(), user.getAge());
			return true;
		}
	}
}

不安全的写法测试

package org.example.chm3;

import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;

/**
 * @author jianan
 * @date 2021/7/6 15:42:53
 */
public class TestCHM3 {
	public static void main(String[] args) throws InterruptedException {
		int threadCount = 8;
		ForkJoinPool forkJoinPool = new ForkJoinPool(threadCount);
		forkJoinPool.execute(() -> {
			IntStream.range(0, threadCount).mapToObj(i -> new User("张三", i))
					.parallel()
					.forEach(UserService::registerUnsafe);

		});

		TimeUnit.SECONDS.sleep(1);
	}
}

/*
[2021-07-06 15:54:21,117] [ForkJoinPool-1-worker-15] INFO org.example.chm3.UserService.register(UserService.java:20): 用户已存在
[2021-07-06 15:54:21,119] [ForkJoinPool-1-worker-1] INFO org.example.chm3.UserService.register(UserService.java:24): 用户注册成功, 张三,0
[2021-07-06 15:54:21,119] [ForkJoinPool-1-worker-13] INFO org.example.chm3.UserService.register(UserService.java:24): 用户注册成功, 张三,6
[2021-07-06 15:54:21,119] [ForkJoinPool-1-worker-5] INFO org.example.chm3.UserService.register(UserService.java:24): 用户注册成功, 张三,2
[2021-07-06 15:54:21,119] [ForkJoinPool-1-worker-3] INFO org.example.chm3.UserService.register(UserService.java:24): 用户注册成功, 张三,5
[2021-07-06 15:54:21,117] [ForkJoinPool-1-worker-9] INFO org.example.chm3.UserService.register(UserService.java:20): 用户已存在
[2021-07-06 15:54:21,117] [ForkJoinPool-1-worker-7] INFO org.example.chm3.UserService.register(UserService.java:20): 用户已存在
[2021-07-06 15:54:21,117] [ForkJoinPool-1-worker-11] INFO org.example.chm3.UserService.register(UserService.java:20): 用户已存在
 */

安全的写法测试

package org.example.chm3;

import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;

/**
 * @author jianan
 * @date 2021/7/6 15:56:34
 */
public class TestCHM4 {
	public static void main(String[] args) throws InterruptedException {
		int threadCount = 8;
		ForkJoinPool forkJoinPool = new ForkJoinPool(threadCount);
		forkJoinPool.execute(() -> {
			IntStream.range(0, threadCount).mapToObj(i -> new User("张三", i))
					.parallel()
					.forEach(UserService::registerSafe);

		});

		TimeUnit.SECONDS.sleep(1);
	}
}

/*
[2021-07-06 15:57:52,678] [ForkJoinPool-1-worker-9] INFO org.example.chm3.UserService.register2(UserService.java:32): 用户已存在
[2021-07-06 15:57:52,678] [ForkJoinPool-1-worker-1] INFO org.example.chm3.UserService.register2(UserService.java:32): 用户已存在
[2021-07-06 15:57:52,678] [ForkJoinPool-1-worker-11] INFO org.example.chm3.UserService.register2(UserService.java:32): 用户已存在
[2021-07-06 15:57:52,680] [ForkJoinPool-1-worker-5] INFO org.example.chm3.UserService.register2(UserService.java:32): 用户已存在
[2021-07-06 15:57:52,680] [ForkJoinPool-1-worker-7] INFO org.example.chm3.UserService.register2(UserService.java:32): 用户已存在
[2021-07-06 15:57:52,680] [ForkJoinPool-1-worker-15] INFO org.example.chm3.UserService.register2(UserService.java:32): 用户已存在
[2021-07-06 15:57:52,679] [ForkJoinPool-1-worker-13] INFO org.example.chm3.UserService.register2(UserService.java:32): 用户已存在
[2021-07-06 15:57:52,678] [ForkJoinPool-1-worker-3] INFO org.example.chm3.UserService.register2(UserService.java:36): 用户注册成功, 张三,5
 */

笔记:

 这里我们使用了Map提供的putIfAbsent接口,其含义是如果 key 已经存在则返回存储的对象,否则返回null。


 putIfAbsent接口定义的时候不是线程安全的,但ConcurrentHashMap在实现的时候将这个方法实现为线程安全。

在这个场景中如果不使用putIfAbsent就要对register(User user)方法加锁,对于性能的影响更大。

你可能感兴趣的:(#,java多线程,java,http,服务器)