锁是否正确完成

时间:2015-03-24 22:20:29

标签: java multithreading locks

我正在读取UDP源,然后解码并写入MSMQ(消息队列)。

我创建了一个调用UDPReader的新线程。反过来,UDPReader创建一个线程池并调用类ipaddrConnection。在ipaddrConnection中运行包含一个while循环,它连续从Multicast套接字读取数据包并将其推送到类parseUDP。从parseUDP解码并最终推送到写入MSMQ的类。我相信当我遇到ipaddrConnection中的while循环时,我没有正确锁定线程,因为线程正试图写入MSMQ中的相同内存位置。我认为通过将我的锁置于while循环中,池中的每个线程将在“Critical Section”中有自己的时间1.接收数据包然后2.decode并写入MSMQ。我仍在学习并发性并寻求一些帮助。我提供了一个崩溃转储文件,我不明白如何正确读取和我的UDPReader和ipaddrConnection类。 parseUDP调用一个类来解码数据包,该类调用MSMQ类来写入内存。所有这些都在我的关键部分。

class UDPReader implements Runnable
{
    private final String ip, socket, queue, threadName;
    private final JTextArea screen;

    UDPReader(String ip, String socket, String queue, String threadName, JTextArea screen) 
    {
        this.ip = ip;
        this.socket = socket;
        this.queue = queue;
        this.threadName = threadName;
        this.screen = screen;
    }

    public void run()
    {
        screen.append("Thread " + threadName + " running\n\n");
        ExecutorService executor = Executors.newFixedThreadPool(5);
        Runnable reader = new ipaddrConnection(ip, socket, queue);
        executor.execute(reader);
    }

}

public final class ipaddrConnection implements Runnable
{
    private final ReentrantLock lock = new ReentrantLock();
    byte[] bytes = new byte[(int)100000];
    InetAddress group; 
    MulticastSocket s;
    DatagramPacket packet = new DatagramPacket(bytes, bytes.length);
    private String queue;

    public ipaddrConnection(String ip, String socket, String queue) {
        try {
            this.s = new MulticastSocket(Integer.parseInt(socket));
            this.group = InetAddress.getByName(ip);
            this.queue = queue;
        } catch (IOException ex) {
            Logger.getLogger(ipaddrConnection.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

        @Override
        public void run() {
            try {
                parseUDP p = new parseUDP(queue);
                s.joinGroup(group);
                s.setSoTimeout(95000);

                try{
                    while(true){
                        lock.lock();
                        s.receive(packet);
                        p.parseUDP(packet.getData());
                    } 
                }finally {
                    lock.unlock();
                }


             } catch (SocketException ex) {
                Logger.getLogger(ipaddrConnection.class.getName()).log(Level.SEVERE, null, ex);
            } catch (IOException ex) {
                Logger.getLogger(ipaddrConnection.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

}

崩溃报告 https://drive.google.com/file/d/0B4GWNCU6_CBlM2tJNGJqNzRVazg/view?usp=sharing

3 个答案:

答案 0 :(得分:0)

在你的代码中,你的锁没有做任何有用的事情。

每个线程都有自己的锁,因此一次可以有多个线程使用队列(因为线程1锁定了锁定1,线程2锁定了锁定2,并且没有什么能阻止它们使用同时排队)。

如果您在代码中创建lock字段static,则线程将使用相同的锁。

你可能仍有问题,因为线程永远不会释放锁(除非遇到异常),所以只允许一个线程工作:

try{
    while(true){
        lock.lock();
        s.receive(packet);
        p.parseUDP(packet.getData());
    } 
}finally {
    lock.unlock();
}

请注意线程解锁的唯一方法是,是否存在异常?

可能想要更像这样的东西:

while(true) {
    s.receive(packet);
    try {
        lock.lock();
        s.parseUDP(packet.getData());
    } finally {
        lock.unlock();
    }
}

- 使用这种结构,线程只会在解析数据包时保持锁定,而不是在接收数据包时。 (我不知道这是否是你真正想要的)

答案 1 :(得分:0)

ExecutorService executor = Executors.newFixedThreadPool(5);
Runnable reader = new ipaddrConnection(ip, socket, queue);
executor.execute(reader);

此代码实际上是单线程的,因为虽然池有五个线程,但您只使用一个。

答案 2 :(得分:0)

  1. 让UDPReader实现Runnable并且它的run()实现至少不是惯用的。
  2. 正如immibis所提到的,您的锁定对象不会在线程之间共享,并且它们不会提供您正在寻找的保护。
  3. 只有当您退出while (true) { ... }时,才会解锁。考虑到这一点,您可能需要考虑以下内容:

        public class UDPReader {
            ...
    
            UDPReader(String ip, String socket, String queue, String threadName, JTextArea screen, numberOfThreads) {
                ...
                this.numberOfThreads = numberOfThreads;
                this.lock = new ReentrantLock();
            }
    
            public void run() {
                ExecutorService executor = Executors.newFixedThreadPool(numberOfThreads);
                for (int i = 0; i < numberOfThreads; i++){
                    executor.execute(new ipaddrConnection(ip, socket, queue, lock));
                }
            }
         }
    
    
         public final class ipaddrConnection implements Runnable {
            private lock ;
            ...
    
            public ipaddrConnection(String ip, String socket, String queue, ReentrantLock lock) {
                ...
                this.lock = lock;
            }
    
            @Override
            public void run() {
                    ...
                    while (true) {
                        try {
                            lock.lock();
                            s.receive(packet);
                            p.parseUDP(packet.getData());
                        } finally {
                            lock.unlock();
                        }
                    }
                 ....
            }
        }
    }