前面说到了Java中的同步问题。下面通过一个小小的实例程序来演示Java中的同步方法。其中对前文提到的Counter类做了稍微的修改。
public class Counter { private int c = 0; public void increment() { System.out.println("before increment, c = " + c); c++; try { Thread.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("after increment, c = " + c); } public void decrement() { System.out.println("before decrement, c = " + c); c--; try { Thread.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("after decrement, c = " + c); } public int value() { return c; } }
在上面的Counter类的实现中,分别对increment和decrement方法中增加了sleep(5)的调用,这样做的目的是为了放大两个线程对同一对象的方法调用时的交错效果。
下面是两个线程。在ThreadA中调用了10次increment()方法;在ThreadB中调用了10次decrement()方法。
Thread:
public class ThreadA implements Runnable { private Counter c; public ThreadA(Counter c) { this.c = c; } @Override public void run() { for (int i = 0; i < 10; i++) { this.c.increment(); } } }
ThreadB:
public class ThreadB implements Runnable { private Counter c; public ThreadB(Counter c) { this.c = c; } @Override public void run() { for (int i = 0; i < 10; i++) { this.c.decrement(); } } }
主程序如下:其中生成了两个线程threadA和ThreadB,他们共享Counter c。
public class Main { public static void main(String[] args) { Counter c = new Counter(); ThreadA a = new ThreadA(c); ThreadB b = new ThreadB(c); Thread threadA = new Thread(a); Thread threadB = new Thread(b); threadA.start(); threadB.start(); } }
执行上面的代码,可能的结果如下:
before increment, c = 0
before decrement, c = 1
after increment, c = 0
before increment, c = 0
after decrement, c = 1
before decrement, c = 1
after increment, c = 0
before increment, c = 0
after decrement, c = 1
before decrement, c = 1
after increment, c = 0
before increment, c = 0
after decrement, c = 1
before decrement, c = 1
after increment, c = 0
before increment, c = 0
after decrement, c = 1
before decrement, c = 1
after increment, c = 0
before increment, c = 0
after decrement, c = 1
before decrement, c = 1
after increment, c = 0
before increment, c = 0
after increment, c = 1
before increment, c = 1
after decrement, c = 2
before decrement, c = 2
after decrement, c = 1
before decrement, c = 1
after increment, c = 0
before increment, c = 0
after increment, c = 1
before increment, c = 1
after decrement, c = 2
before decrement, c = 2
after increment, c = 1
after decrement, c = 1
before decrement, c = 1
after decrement, c = 0
从上面的输出结果中我们不难看出出现了严重的交错现象! 在increment或者是decrement方法中输出before和after本应该是成对连续出现的。但输出结果却不是如此。
将上面代码的increment()和decrement()方法用synchronized 修饰后,重新运行该程序,输出结果如下:
before increment, c = 0
after increment, c = 1
before increment, c = 1
after increment, c = 2
before decrement, c = 2
after decrement, c = 1
before increment, c = 1
after increment, c = 2
before decrement, c = 2
after decrement, c = 1
before decrement, c = 1
after decrement, c = 0
before decrement, c = 0
after decrement, c = -1
before decrement, c = -1
after decrement, c = -2
before increment, c = -2
after increment, c = -1
before decrement, c = -1
after decrement, c = -2
before decrement, c = -2
after decrement, c = -3
before decrement, c = -3
after decrement, c = -4
before decrement, c = -4
after decrement, c = -5
before increment, c = -5
after increment, c = -4
before decrement, c = -4
after decrement, c = -5
before increment, c = -5
after increment, c = -4
before increment, c = -4
after increment, c = -3
before increment, c = -3
after increment, c = -2
before increment, c = -2
after increment, c = -1
before increment, c = -1
after increment, c = 0
这样输出结果和没有增加synchronized修饰符时的大不相同:单独一次的increment和decrement方法并没有出现交错的现象。只是连续10次的increment()和decrement ()有交错。
至少,我们从上面的实例程序中可以看到synchronized方法的作用了。
另外,我们还可以使用同步语句(也就是使用Counter对象的同步锁)来代替上面的同步方法,其效果是一样的。有兴趣的网友可以自己尝试一下。