我正在使用spring框架编写应用程序。我有一个用户管理应用程序,可以在其中创建用户及其地址,每个用户及其地址都会收到一个使用其他类生成的ID。因为每个ID生成都需要时间,所以我想在一个线程中创建ID。我希望每个地址创建都等到它的ID准备好为止,以便用户使用。
尝试使用等待,但有时看起来效果不佳,我不希望所有地址都等到所有地址都写完之后,我宁愿每次等待都只等待自己的ID。
public UserDto createUser(UserDto userDto) {
UserEntity storedUserDetails = userRepository.findByEmail(userDto.getEmail());
if (userRepository.findByEmail(userDto.getEmail()) != null) {
throw new RuntimeException("Record already exists");
}
final String[] userId = new String[1];
final CountDownLatch userIdLatch = new CountDownLatch(1);
int addressesSize = userDto.getAddresses().size();
final String[] addressesId = new String[addressesSize];
final CountDownLatch[] addressesIdLatches = new CountDownLatch[addressesSize];
for (int i = 0; i < addressesSize; i++) {
addressesIdLatches[i] = new CountDownLatch(1);
}
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < addressesSize; i++) {
addressesId[i] = utils.generateAddressId(30);
addressesIdLatches[i].countDown();
}
userId[0] = utils.generateUserId(30);
userIdLatch.countDown();
}
});
thread.start();
for (int i = 0; i < addressesSize; i++) {
AddressDto addressDto = userDto.getAddresses().get(i);
addressDto.setUserDetails(userDto);
try {
addressesIdLatches[i].await();
} catch (InterruptedException e) {
e.printStackTrace();
}
addressDto.setAddressId(addressesId[i]);
userDto.getAddresses().set(i, addressDto);
}
ModelMapper modelMapper = new ModelMapper();
UserEntity userEntity = modelMapper.map(userDto, UserEntity.class);
try {
userIdLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
userEntity.setUserId(userId[0]);
userEntity.setEncryptedPassword(bCryptPasswordEncoder.encode(userDto.getPassword()));
UserEntity storedUserEntity = userRepository.save(userEntity);
UserDto returnedValue = new UserDto();
BeanUtils.copyProperties(storedUserEntity, returnedValue);
return returnedValue;
}
ER->每个地址都等待,直到其ID就绪为止(无需等待其他地址)。
AR->引发异常
答案 0 :(得分:0)
非常简单的例子
public class Main {
public static void main(String[] args) throws Exception {
User user = new User();
int count = 100;
user.adrs = new String[count];
while (count > 0) {
count--;
user.adrs[count] = "adr" + count;
}
int userAddressesCount = user.adrs.length;
ExecutorService service = Executors.newFixedThreadPool(userAddressesCount);
Map<String, Future<String>> adrMap = new HashMap<>();
for (int i = 0; i < userAddressesCount; i++) {
String oldAdr = user.adrs[i];
adrMap.put(oldAdr, service.submit(new AddressReceiver(oldAdr)));
}
for (String key : adrMap.keySet()) {
int idxOfAdr = user.findIdxOfAdr(key);
//something like enrich address
user.adrs[idxOfAdr] = adrMap.get(key).get();
System.out.println("ASYNC: " + user.adrs[idxOfAdr]);
}
System.out.println("#################################");
for(String adr: user.adrs) {
System.out.println(adr);
}
service.shutdown();
}
static class User {
String id;
String[] adrs;
private int findIdxOfAdr(String adr) {
for (int i = 0; i < this.adrs.length; i++) {
if (this.adrs[i].equals(adr)) return i;
}
return -1;
}
}
static class AddressReceiver implements Callable<String> {
private final String someValueForGeneration;
public AddressReceiver(String someValueForGeneration) {
this.someValueForGeneration = someValueForGeneration;
}
@Override
public String call() throws Exception {
Thread.sleep((int) (Math.random() * 10000));
return someValueForGeneration + " enrich adr";
}
}
}