我正在修改Java服务器软件。整个应用程序是单线程的。我的更改之一需要花费很多时间,因此我决定异步执行此操作以避免冻结主线程。

这是原始代码的示例(不是真实代码,仅是示例):

public class Packet {
    private final byte[] data = new byte[1024];

    public void setData(int index, byte data) {
        this.data[index] = data;
    }

    public byte getData(int index) {
        return data[index];
    }

    public void sendPacket(ClientConnection clientConnection) {
        clientConnection.sendPacket(data);
    }
}

当前,这是我的代码(请看注释):
public class Packet {
    private final byte[] data = new byte[1024];

    public void setData(int index, byte data) {
        synchronized (this) {
            this.data[index] = data;
        }
    }

    public byte getData(int index) {
        return data[index];
    }

    public void sendPacket(final ClientConnection clientConnection) {
        //This state of data should be sent
        new Thread(new Runnable() {
            @Override
            public void run() {
                //The thread is now running
                //The main-thread can move on
                //The main-thread can also modify data now because we are not inside the synchronized block
                //But it should not because the state of data when the method sendPacket was called should be sent
                synchronized (Packet.this) {
                    thisTakesMuchTime(data);
                    clientConnection.sendPacket(data);
                }
            }
        }).start();
    }
}

我实际上正在寻找的是这样的:
public class Packet {
    private final byte[] data = new byte[1024];

    public void setData(int index, byte data) {
        //wait for unlock
        this.data[index] = data;
    }

    public byte getData(int index) {
        return data[index];
    }

    public void sendPacket(final ClientConnection clientConnection) {
        //lock
        new Thread(new Runnable() {
            @Override
            public void run() {
                thisTakesMuchTime(data);
                clientConnection.sendPacket(data);
                //unlock
            }
        }).start();
    }
}

问题:在Java中,这种锁的最佳实现是什么?我是否应该自己使用AtomicInteger做到这一点。

编辑:看看我对我当前的实现的答案。

最佳答案

您可以复制数据并发送副本,以避免并发。

public class Packet {
    private final byte[] data = new byte[1024];

    public void setData(final int index, final byte data) {
        this.data[index] = data;
    }

    public byte getData(final int index) {
        return data[index];
    }

    public void sendPacket(final ClientConnection clientConnection) {
        byte[] dataToSend = new byte[1024];
        System.arraycopy(data, 0, dataToSend, 0, 1024);
        new Thread(new Runnable() {
            @Override public void run() {
                clientConnection.sendPacket(dataToSend);
            }
        }).start();
    }
}

使用CopyOnWriteArrayList类似于下面的代码,它还避免了并发但效率不高(假设您将比setData调用sendPacket的频率更高):
public class Packet {
    private byte[] data = new byte[1024];

    public void setData(final int index, final byte data) {
        byte[] newData = new byte[1024];
        System.arraycopy(data, 0, newData, 0, 1024);
        newData[index] = data;
        this.data = newData;
    }

    public byte getData(final int index) {
        return data[index];
    }

    public void sendPacket(final ClientConnection clientConnection) {
        new Thread(new Runnable() {
            @Override public void run() {
                clientConnection.sendPacket(data);
            }
        }).start();
    }
}

10-07 13:19
查看更多