简体   繁体   English

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

[英]Java concurrency issue - Locks and Synchronize method

I am working on Re entrant locks and trying to correlate it with Synchronize. 我正在研究Re entrant锁并试图将它与Synchronize相关联。 However both these classes are giving me unexpected results. 然而,这两个类都给了我意想不到的结果。 I am expecting the arrayList to have 0 to 9. but that value never comes in both these programs. 我期望arrayList有0到9.但这个值永远不会出现在这两个程序中。 Please suggest. 请建议。 With 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();
    }
}

With synchronize: 同步:

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();
    }

}

There are so many things wrong with this. 这有很多问题。

Firstly, you expect it to contain 0..9, but you call count++ before al.add(count) , which means you should actually expect 1..10. 首先,你希望它包含0..9,但你在al.add(count)之前调用count++ ,这意味着你实际上应该期望1..10。

Since you're using a new LockWithSynchronize or Locking each time, there isn't actually any shared lock -- each instance gets its own lock, which never conflicts with any other lock, which means your count variable is completely unprotected. 由于每次都使用新的LockWithSynchronizeLocking ,实际上没有任何共享锁 - 每个实例都有自己的锁,它永远不会与任何其他锁冲突,这意味着你的count变量完全不受保护。 And you're likely to periodically get either a corrupted ArrayList due to add being called on multiple threads without synchronization, or ConcurrentModificationException or similar. 并且由于在没有同步的情况下在多个线程上调用add ,或者ConcurrentModificationException ,您可能会定期获取损坏的ArrayList

Try this: 尝试这个:

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();
}

Note that instead of a new Locking every time, we're reusing the same instance, and what you expect now happens: you spawn ten threads very quickly, each of which wait for two seconds before trying to call producer() . 请注意,我们不是每次都使用新的Locking ,而是重复使用相同的实例,并且您现在的期望是:您非常快速地生成十个线程,每个线程在尝试调用producer()之前等待两秒钟。 One thread gets the lock, while the other nine block. 一个线程获得锁定,而另一个线程获得锁定。 The one that gets the lock then waits with the lock for five seconds before exiting, at which point the next thread gets the lock, waits for five seconds, and exits, etc. So this'll take close to a minute to run. 获得锁定的那个然后在退出之前等待锁定五秒钟,此时下一个线程获得锁定,等待五秒钟,然后退出等等。所以这将花费近一分钟来运行。

Similar modification fixes the other one, too. 类似的修改也修复了另一个。

Your synchronize does not protect the static variable - synchonize only locks the monitor of the current this object when use like that. 您的同步不保护静态变量 - synchonize仅在使用时锁定当前this对象的监视器。 No produce() invocation will ever wait for any other in the code you posted. 没有produce()调用会等待您发布的代码中的任何其他内容。 Lock on something shared - say LockWithProducer.class, for example. 锁定共享的东西 - 比如说LockWithProducer.class。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM