如何在java中使用内部锁?

时间:2016-01-09 09:40:04

标签: java multithreading concurrency synchronization

我正在阅读Oracle提供的官方Java Tutorial,我想将我的知识付诸实践。

我希望看到Thread Interference正在运行并使用Intrinsic Locks and Synchronization解决它。所以我创建了一个名为Counter with:

的类
  • 两个都初始化为0的字段。
  • 递增和递减其值的方法。
  • 打印出值的方法。

public class Apple {
    public static void main(String[] args) {
        Counter myCounter = new Counter();
        Thread a = new Thread(myCounter);
        Thread b = new Thread(myCounter);

        a.start();
        b.start();
    }
}

class Counter implements Runnable {
    public int a = 0;
    public int b = 0;

    void incA() {
        ++a;
    }

    void decA() {
        --a;
    }

    void incB() {
        ++b;
    }

    void decB() {
        --b;
    }

    void printValues() {
        System.out.println("a: " + a + " | b: " + b);
    }

    public void run() {
        for (int i = 0; i < 10; i++) {
            incA();
            decA();
            incB();
            decB();
            printValues();
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

首先,我运行我的程序而不使用内部锁或同步,输出是我所期望的,线程干扰。

...
a: 0 | b: 0
a: 0 | b: 1
a: 0 | b: 0
a: 1 | b: 0
a: 0 | b: 0
...

现在我想使用内部锁对这个问题进行排序,这样当一个线程递增或递减a时,另一个线程可以同时改变b,而不是使用可以防止这种情况的同步方法。

所以我使用内部锁添加了两个新字段(锁)和同步块。这是新代码:

class Counter implements Runnable {
    public int a = 0;
    public int b = 0;
    Object lock1 = new Object();
    Object lock2 = new Object();

    void incA() {
        synchronized (lock1) {
            ++a;
        }
    }

    void decA() {
        synchronized (lock1) {
            --a;
        }
    }

    void incB() {
        synchronized (lock2) {
            ++b;
        }
    }

    void decB() {
        synchronized (lock2) {
            --b;
        }
    }

    void printValues() {
        System.out.println("a: " + a + " | b: " + b);
    }

    public void run() {
        for (int i = 0; i < 10; i++) {
            incA();
            decA();
            incB();
            decB();
            printValues();
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

我没有对主要方法进行任何更改,所以我没有包含它。但我运行了这个代码三次,这是最后一次尝试的输出:

...
a: 0 | b: 0
a: 0 | b: 0
a: 0 | b: 1
a: 0 | b: 0

我做错了什么?代码应该如何?

我只想要一个使用内部锁的简单示例代码。

2 个答案:

答案 0 :(得分:4)

int skip = 20; int take=10; List<string> filteredList = records.Skip(skip).Take(take).ToList(); 读取并打印值,而另一个线程递增或递减它们:它不同步。即使它是,它也可以在对另一个线程的{{block type="catalog/product_list" column_count="4" category_id="2" block_name="home.catalog.product.list" template="izotope/products_from_category.phtml"}} printValues()的调用之间读取和打印b

所以你可以拥有

  • 线程1递增b - &gt; b = 1
  • 线程2读取并打印b - &gt; b打印为1
  • 线程1递减b - &gt; b = 0

如果没有人认为b与b不同,那么incB()应该是单个原子操作,通过将这两个调用放在一个同步块中,并且b的读取也应该放入synchronized块,使用相同的锁:

decB()

答案 1 :(得分:1)

如何从printValues()方法中移除run()并在主线程中等待所有线程在打印前完成?主要是:

public static void main(String[] args) throws InterruptedException {
 Counter myCounter = new Counter();
 Thread a = new Thread(myCounter);
 Thread b = new Thread(myCounter);

 a.start();
 b.start();

 a.join();
 b.join();
 myCounter.printValues();
}