同步问题和获取 id 生成的集合计数

Issue with synchronization and getting collection count for id generation

我在使用 nextMessageId() 时遇到问题,它应该 return 为每条创建的消息分配一个新 ID。然而,每隔一段时间它就不会。它 return 是一个已经使用过的值,我不明白为什么。我试过在 IDE 中调试它,但当我单步执行它时它似乎工作正常。

我正在尝试学习如何使用多线程,如何正确同步方法等。我正在模拟用户发送消息的过程。

基本上每次挖出一个区块时,消息都会从缓冲区复制到当前区块,然后将新区块添加到区块集合中。除了 nextMessageId() 之外,一切似乎都工作正常。感谢任何帮助。

我不想 post 不必要的代码来保持这个 post 尽可能干净,如果需要更多信息,请告诉我。

用户服务class:

public final class UserService extends Service<User, String> {
    ...

    @Override
    public void submit(String message, User user) {
        synchronized (Blockchain.class) {
            MessageEntry messageEntry = MessageEntry.newInstance(repo.nextMessageId(), message, user);
            repo.postMessage(messageEntry);
        }
    }
}

矿工服务class:

public final class MinerService extends Service<Miner, Long> {
    ...

    public void submit(Long number, Miner miner) {
        if (repo.getCurrentBlock().hash(number).startsWith(repo.prefix())) {
            synchronized (Blockchain.class) {
                if (repo.getCurrentBlock().hash(number).startsWith(repo.prefix())) {
                    repo.createBlock(number, miner);
                }
            }
        }
    }
}

Blockchain.class

public class Blockchain {
    ...

    private Deque<Block> blocks;
    private Deque<DataEntry<?>> messageBuffer;
    private Block currentBlock;

    ...

    public long nextMessageId() {
        return blocks.stream()
                .mapToLong(block -> block.getData().size())
                .sum() + messageBuffer.size() + 1L;
    }

    public void postMessage(DataEntry<?> dataEntry) {
        messageBuffer.offerLast(dataEntry);
    }

    public void createBlock(long number, Miner miner) {
        long duration = (new Date().getTime() - currentBlock.getTimestamp()) / 1000;
        Block.ProofOfWork proofOfWork = new Block.ProofOfWork(number, duration, updateN(duration), miner);
        currentBlock.setProofOfWork(proofOfWork);

        if (blocks.offerLast(currentBlock)) {
            currentBlock = generateBlock();
            currentBlock.setData(messageBuffer);
            messageBuffer.clear();
            stateManager.save();
        }
    }
    ...
}

生成5个区块后的消息输出:

Block:
Created by miner # 4
Id: 1
Timestamp: 1637995160818
Magic number: 6489039085832314491
Hash of the previous block: 
0
Hash of the block: 
7cecb0d73c5bbfa925f2c04fba90778c8431e43dc3abd1b0faf1dbc23400321c
Block data: no messages
Block was generating for 0 seconds
N was increased to 1

Block:
Created by miner # 6
Id: 2
Timestamp: 1637995160897
Magic number: 5017000130559711273
Hash of the previous block: 
7cecb0d73c5bbfa925f2c04fba90778c8431e43dc3abd1b0faf1dbc23400321c
Hash of the block: 
0ff1a96574cd8cf9db8c91eeb436df8efd084582251c081409e43e0f17069d51
Block data: 
1 Charles: Life is good
2 Aramys: How bout' those Dolphins?
3 Evelio: Life is good
4 Armando: I love Java
5 Evelio: I love Java
6 Armando: What is the meaning of life?
7 Aramys: I love basketball
8 Charles: How bout' those Dolphins?
Block was generating for 0 seconds
N was increased to 2

Block:
Created by miner # 3
Id: 3
Timestamp: 1637995160918
Magic number: -4429177738817892095
Hash of the previous block: 
0ff1a96574cd8cf9db8c91eeb436df8efd084582251c081409e43e0f17069d51
Hash of the block: 
007577aca398b8fa711229b95f2abb0f959aa73fbaa8939516ca1bea11a467fa
Block data: no messages
Block was generating for 0 seconds
N was increased to 3

Block:
Created by miner # 5
Id: 4
Timestamp: 1637995160932
Magic number: 2352460595297940125
Hash of the previous block: 
007577aca398b8fa711229b95f2abb0f959aa73fbaa8939516ca1bea11a467fa
Hash of the block: 
00053d5c5b0e958f828c12ae74469fdce1e840334cfa4a431504239133c7c612
Block data: 
9 Evelio: How are you?
Block was generating for 0 seconds
N was increased to 4

Block:
Created by miner # 5
Id: 5
Timestamp: 1637995160951
Magic number: 3338207044781263189
Hash of the previous block: 
00053d5c5b0e958f828c12ae74469fdce1e840334cfa4a431504239133c7c612
Hash of the block: 
000093d155de9a54e2143b97d752b7d57031056ec6eb07b9672c5c0815fd9272
Block data: 
9 Armando: This chat is garbage
10 Charles: Interesting...
11 Aramys: Will I ever make decent money?
Block was generating for 0 seconds
N was increased to 5

[1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 10, 11]

编辑:问题是我没有考虑 currentBlock 中保存的 DataEntry(消息)。这解决了问题:

public long nextMessageId() {
    return blocks.stream()
            .mapToLong(block -> block.getData().size())
            .sum() + currentBlock.getData().size() + messageBuffer.size() + 1L;
}

来自您的评论:

The nextMessageId() counts the size of the collection in each block

NextMessageId:

    public long nextMessageId() {
        return blocks.stream()
                .mapToLong(block -> block.getData().size())
                .sum() + messageBuffer.size() + 1L;
    }

您不是还添加了一个额外的 messagebuffer 尺寸吗?

并且在您的 createBlock 方法中,您将清除此缓冲区。于是ID又变小了