无法使用Thread同步进程

问题描述 投票:4回答:5

我正在测试我的技能而不是Thread的行为。当我实现Runnable接口和synchronized运行方法时,我得到了绝对的结果。但是,当我扩展Thread课程时,结果是不可预测的。以下是两个案例。我认为,两种情况下的线程都使用相同的资源。

案例1 Runnable

class Counter{
    int count;
    public void doCount(){
        count=count+1;
    }
    public int getCount(){
        return count;
    }
}
public class One implements Runnable{
    Counter counter = new Counter(); // common object to be shared with two threads
    public void run(){
        synchronized (this) {
            for(int i=0;i<10000;i++){
                counter.doCount();
            }   
        }
    }
    public static void main(String[] args) throws InterruptedException {
        One one = new One();
        Thread t1 = new Thread(one);// using same resource 'one'
        Thread t2 = new Thread(one);// using same resource 'one'
        t1.start();
        t2.start();
        Thread.sleep(2000); // to give both threads time to complete
        System.out.println(one.counter.getCount());
    }
}

案例2 Thread

class Counter{
    int count;
    public void doCount(){
        count=count+1;
    }
    public int getCount(){
        return count;
    }
}
public class One extends Thread{
    Counter counter; //common object to be shared with two threads
    One(Counter counter){
        this.counter = counter; 
    }
    public void run(){
        synchronized (this) {
            for(int i=0;i<10000;i++){
                counter.doCount();
            }   
        }
    }
    public static void main(String[] args) throws InterruptedException {
        Counter counter = new Counter();
        One o1 = new One(counter);// using same resource counter
        One o2 = new One(counter);// using same resource counter
        o1.start();
        o2.start();
        Thread.sleep(2000); // to give both threads time to complete
        System.out.println(counter.getCount());
    }
}

对于案例1,我每次都输出20000。但对于案例2,我每次都会得到随机值。为什么会这样?情况2也在两个线程中使用相同的资源,那么为什么他们停止获取synchronized。任何人都能解释一下......我疯了!

java multithreading synchronization
5个回答
1
投票

synchronized (this)有缺陷。在这种情况下,您有2个实例:o1和02.synchronized (counter)应该工作但不是理想的解决方案。

理想情况下,只是为了测试,我会使用私人锁。

class Counter{
    final Object lock= new Object();
    int count;
    public void doCount(){
        synchronized (lock){
            count=count+1;
        }
    }
    public int getCount(){
        synchronized (lock) {
            return count;
        }
    }
}

sleep更好的方法是使用Thread.join()


2
投票

在这个例子中,我只是在计数器实例上进行同步,而不是按照其他人的建议将同步放在Counter类中。这使得Counter类变得简单并且不知道任何潜在的线程问题,这些问题仅在多个线程使用该类时才会出现。

所以代码是:

public class Counter {
    int count;
    public void doCount() {
        count=count+1;
    }
    public int getCount() {
        return count;
    }
}

public class CountRunner implements Runnable {
    Counter counter; 
    public CountRunner(Counter counter){
        this.counter = counter; 
    }
    public void run() {
        synchronized (counter) {
            for(int i=0;i<10000;i++){
                counter.doCount();
            }   
        }
    }
}

public class CountThread extends Thread {
    Counter counter; 
    public CountThread(Counter counter){
        this.counter = counter; 
    }
    public void run() {
        synchronized (counter) {
            for(int i=0;i<10000;i++){
                counter.doCount();
            }   
        }
    }
}

public class App {
    public static void main(String[] args) throws InterruptedException {
        countRunnerTest();
        countThreadTest();
    }

    public static void countRunnerTest() {
        Counter counter = new Counter();
        CountRunner countRunner = new CountRunner(counter);
        Thread t1 = new Thread(countRunner);
        Thread t2 = new Thread(countRunner);
        t1.start();
        t2.start();
        Thread.sleep(2000); 
        System.out.printf("CountRunnerTest result=%s", counter.getCount());
    }

    public static void countThreadTest() {
        Counter counter = new Counter();
        CountThread t1 = new CountThread(counter);
        CountThread t2 = new CountThread(counter);
        t1.start();
        t2.start();
        Thread.sleep(2000);
        System.out.printf("CountThread  result=%s", counter.getCount());
    }

}

1
投票

在第二种情况下,基础“this”对象指的是One类的两个不同实例,即o1和o2。 for循环独立运行,在两个不同的实例上有对象监视器锁,因此很明显这里的计数器修改是非同步的。

通常,标准数据结构会在这种情况下抛出ConcurrentModificationException。


1
投票

当你使用synchronized (this)时,它会锁定你调用方法的对象。

在你创建的案例一中

One one = new One();

并传递给每个方法,因此两者都使用相同的对象作为锁。

在案例2中,您正在创建两个对象,并且两个都使用不同的对象作为锁。您可以使用计数器作为锁而不是此,这将解决您的问题。

 One o1 = new One(counter);// using same resource counter
 One o2 = new One(counter);

1
投票

好的,首先你应该知道实现runnable和继承线程here之间的区别。然后,阅读this以清楚地了解添加同步的porpuses。

无论如何,检查同步功能内的this。在第一种情况下,它与One one = new One(One)有关...而第二种One one = new One(One)它与自身有关。两者都是同步的,但第一个与第一个实例同步。但是,第二个与第二个实例同步。尝试使用锁它应该工作。

© www.soinside.com 2019 - 2024. All rights reserved.