Java并发问题-锁和同步方法

3

我正在研究可重入锁,并试图将其与Synchronize相关联。但是这两个类都给我带来了意外的结果。我期望arrayList中有0到9的值,但是在这两个程序中从未出现过。请建议。

使用lock:

package Threads;

import java.util.ArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Locking {

    Lock lock = new ReentrantLock(true);
    ArrayList<Integer> al = new ArrayList<Integer>();
    static int count = 0;

    public void producer() {
        lock.lock();
        count++;
        al.add(count);
        System.out.println(al);
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
        // System.out.println("I came out of this block:"+Thread.currentThread().getName());
    }

    public void consumer() {
    }

    public static void main(String[] args) {
        // ExecutorService ex= Executors.newCachedThreadPool();
        ExecutorService ex = Executors.newFixedThreadPool(10);

        for (int i = 0; i < 10; i++) {
            ex.submit(new Runnable() {

                @Override
                public void run() {
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    new Locking().producer();
                }

            });
        }
        ex.shutdown();
    }
}

使用同步:

package Threads;

import java.util.ArrayList;
import java.util.Collections;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class LockwithSynchronize {

    ArrayList<Integer> al = new ArrayList<Integer>();
    static int count = 0;

    public synchronized void producer() {
        count++;
        al.add(count);
        System.out.println(al);
        try {
            Thread.sleep(5000);
            // System.out.println("I came out of this block:"+Thread.currentThread().getName());
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        // ExecutorService ex= Executors.newCachedThreadPool();
        ExecutorService ex = Executors.newFixedThreadPool(10);

        for (int i = 0; i < 10; i++) {
            ex.submit(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    new LockwithSynchronize().producer();
                }
            });
        }
        ex.shutdown();
    }

}

你得到了什么输出? - Krease
2个回答

3

这个代码存在很多问题。

首先,你希望它包含0到9,但是在al.add(count)之前调用了count++,这意味着你实际上应该期望1到10。

由于每次都使用新的LockWithSynchronizeLocking,实际上并没有共享锁--每个实例都有自己的锁,这永远不会与任何其他锁冲突,这意味着你的count变量完全没有保护。你可能会定期出现由于没有同步地在多个线程上调用add而导致的损坏的ArrayList,或者ConcurrentModificationException或类似的异常。

尝试这样做:

public static void main(String [] args){

    ExecutorService ex= Executors.newFixedThreadPool(10);

    final Locking producer = new Locking();

    for (int i=0; i<10;i++)
    {
        ex.submit(new Runnable(){

            @Override
            public void run() {
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                producer.producer();
            }

        });
    }

    ex.shutdown();
}

请注意,我们不是每次都创建一个新的Locking实例,而是重复使用同一个实例。现在您可以快速生成十个线程,每个线程在尝试调用producer()之前等待两秒钟。其中一个线程获取锁,而另外九个线程被阻塞。获取锁的线程随后等待五秒钟并退出,此时下一个线程获取锁,等待五秒钟并退出,以此类推。因此,这将需要接近一分钟才能运行。
类似的修改也可以解决另一个问题。

0
你的同步代码没有保护静态变量 - 像这样使用同步只锁住当前对象的监视器。在你发布的代码中,即使是任何其他produce()调用也不会等待。所以需要锁定一些共享资源,比如LockWithProducer.class。

另外,您确切期望什么输出?您真的想要每个LockWithSynchronize都有一个列表吗?还是您试图让所有线程输出到单个列表中? - BadZen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接