Java 多线程等待的最佳实践

Java 多线程等待的最佳实践,java,multithreading,Java,Multithreading,我正在使用spring框架编写一个应用程序。我有一个用户管理应用程序,我可以在其中创建用户及其地址,每个用户及其地址接收一个ID,该ID使用另一个类生成。因为每个ID生成都需要时间,所以我想在线程中创建ID。我希望每个地址的创建都要等到它的ID准备好了,用户也准备好了 尝试使用wait,但有时看起来不太顺利,我不是所有地址都要等到全部完成,我更喜欢每次等待都只等待它自己的ID public UserDto createUser(UserDto userDto) { UserEntit

我正在使用spring框架编写一个应用程序。我有一个用户管理应用程序,我可以在其中创建用户及其地址,每个用户及其地址接收一个ID,该ID使用另一个类生成。因为每个ID生成都需要时间,所以我想在线程中创建ID。我希望每个地址的创建都要等到它的ID准备好了,用户也准备好了

尝试使用wait,但有时看起来不太顺利,我不是所有地址都要等到全部完成,我更喜欢每次等待都只等待它自己的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;
}
public UserDto createUser(UserDto UserDto){
UserEntity storedUserDetails=userRepository.findByEmail(userDto.getEmail());
if(userRepository.findByEmail(userDto.getEmail())!=null){
抛出新的RuntimeException(“记录已存在”);
}
最终字符串[]userId=新字符串[1];
最终CountDownLatch useridlotch=新的CountDownLatch(1);
int-AddresseSize=userDto.getAddresses().size();
最终字符串[]地址ID=新字符串[地址大小];
最终倒计时闩锁[]地址设置闩锁=新倒计时闩锁[地址设置];
for(int i=0;i
ER->每个地址等待,直到它的ID准备就绪(无需等待其他地址)

AR->抛出异常

非常简单的示例

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";
    }
}
公共类主{
公共静态void main(字符串[]args)引发异常{
用户=新用户();
整数计数=100;
user.adrs=新字符串[计数];
而(计数>0){
计数--;
user.adrs[count]=“adr”+计数;
}
int useraddresscount=user.adrs.length;
ExecutorService=Executors.newFixedThreadPool(UserAddressCount);
Map adrMap=新的HashMap();
for(int i=0;i

}

在我看来,您的整个多线程解决方案存在缺陷。在这里创建第二个线程有什么意义?除非
setUserDetails()
非常复杂,否则您只是将负载从一个线程移动到另一个线程。也许你应该创建多线程或其他什么?除此之外,使用某种类型的
ExecutorService
Future
s列表可能会使整个应用程序比手动使用
Latch
es和
await()
更简单。请分享一个最小的可复制示例,以便我们可以帮助你。有关更多详细信息,请查看此链接: