Java中的静态同步
在Java中的同步中,已经讨论过Java中的每个对象都具有与其关联的单个锁(也称为监视器)。当线程进入同步方法或者同步块时,它将获取该锁。尝试执行相同代码的所有其他线程(在同步方法或者同步块中)必须等待第一个线程完成并释放锁。
但是,如果我们有多个同一个对象,那该怎么办?在这种情况下,两个单独的线程可以获取这两个对象的锁,并同时使用这些单独的锁输入同步方法或者同步块。如果我们不希望发生这种情况,则需要使用Java进行静态同步。
静态同步
我们必须知道,在Java中标记为静态的变量或者方法属于该类型,而不属于对象,并且此类变量或者方法将在类的实例之间共享。同样,Java中的静态同步也处于类级别而不是实例级别。
静态同步Java示例
让我们尝试通过一个示例来阐明Java中的静态同步。
在这里,我们有一个包含两个方法的类,在一个方法中,有一个for循环从1到5运行,并显示了这些值,在另一个方法中,有5个循环从5到1运行并显示了值。
创建了此类ctr1和ctr2的两个对象。还创建了四个线程,其中两个共享ctr1对象,而另外两个共享ctr2对象。我们所需要的是线程的执行方式应使循环中的值以1,2,3,4,5和5,4,3,2,1的顺序显示。为此,我们还同步了方法increment()和decrement()。
// Class whose object will be shared class Counter{ public synchronized void increment(){ for(int i = 1; i <= 5 ; i++){ System.out.println(Thread.currentThread().getName() + " i - " + i); try { Thread.sleep(50); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } public synchronized void decrement(){ for(int i = 5; i > 0 ; i--){ System.out.println(Thread.currentThread().getName() + " i - " + i); } } } class MyIncrementRunnable implements Runnable{ Counter ctr; MyIncrementRunnable(Counter ctr){ this.ctr = ctr; Thread t = new Thread(this); t.start(); } @Override public void run() { ctr.increment(); } } class MyDecrementRunnable implements Runnable{ Counter ctr; MyDecrementRunnable(Counter ctr){ this.ctr = ctr; Thread t = new Thread(this); t.start(); } @Override public void run() { ctr.decrement(); } } public class SynchronizedDemo { public static void main(String[] args) throws InterruptedException { // Two objects shared among threads Counter ctr1 = new Counter(); Counter ctr2 = new Counter(); // Thread 0 and Thread 1 for increment and decrement with same object MyIncrementRunnable mi1 = new MyIncrementRunnable(ctr1); MyDecrementRunnable md1 = new MyDecrementRunnable(ctr1); // Thread 2 and Thread 3 for increment and decrement with same object MyIncrementRunnable mi2 = new MyIncrementRunnable(ctr2); MyDecrementRunnable md2 = new MyDecrementRunnable(ctr2); } }
输出:
Thread-0 i - 1 Thread-3 i - 5 Thread-3 i - 4 Thread-3 i - 3 Thread-3 i - 2 Thread-3 i - 1 Thread-2 i - 1 Thread-0 i - 2 Thread-2 i - 2 Thread-0 i - 3 Thread-2 i - 3 Thread-0 i - 4 Thread-2 i - 4 Thread-0 i - 5 Thread-2 i - 5 Thread-1 i - 5 Thread-1 i - 4 Thread-1 i - 3 Thread-1 i - 2 Thread-1 i - 1
从输出中可以看到,由于线程0和线程1在同一个对象ctr1上同步,因此这两个线程不会交织。在相同的对象ctr2上以相同的方式同步线程2和线程3,因此这两个线程不会交织。但是,即使线程0获得了锁,线程2仍可以进入同步方法,因为它们都有自己的独立对象锁。
使用静态同步
要解决此问题,我们需要使用静态同步在类级别而不是在实例级别进行同步。使用Java中的静态同步,线程获取与该类关联的Class对象的固有锁定。
在上面的示例中,我们只需要使方法增量()和减量()也成为静态方法即可。
// Class whose object will be shared class Counter{ public static synchronized void increment(){ for(int i = 1; i <= 5 ; i++){ System.out.println(Thread.currentThread().getName() + " i - " + i); try { Thread.sleep(50); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } public static synchronized void decrement(){ for(int i = 5; i > 0 ; i--){ System.out.println(Thread.currentThread().getName() + " i - " + i); } } }
输出:
Thread-0 i - 1 Thread-0 i - 2 Thread-0 i - 3 Thread-0 i - 4 Thread-0 i - 5 Thread-2 i - 1 Thread-2 i - 2 Thread-2 i - 3 Thread-2 i - 4 Thread-2 i - 5 Thread-3 i - 5 Thread-3 i - 4 Thread-3 i - 3 Thread-3 i - 2 Thread-3 i - 1 Thread-1 i - 5 Thread-1 i - 4 Thread-1 i - 3 Thread-1 i - 2 Thread-1 i – 1
Java中的静态同步块
我们还可以在Java中使用静态同步块,而不是使用对象引用,而必须同步类对象本身。
Java中静态同步块的一般形式
Synchronized(CLASS_NAME.class)
范例程式码
在上面的示例中,我们可以将方法增量()和减量()更改为具有带有类引用的同步块。
// Class whose object will be shared class Counter{ public void increment(){ // synchronized block with class reference synchronized(Counter.class){ for(int i = 1; i <= 5 ; i++){ System.out.println(Thread.currentThread().getName() + " i - " + i); try { Thread.sleep(50); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } public void decrement(){ synchronized(Counter.class){ for(int i = 5; i > 0 ; i--){ System.out.println(Thread.currentThread().getName() + " i - " + i); } } } }