乐趣区

关于java:关于对java中synchronized修饰同一个类的两个方法的理解

Java 中同一个类中不同的 synchronized 办法不能够并发执行

多个线程拜访同一个类的 synchronized 办法时, 都是串行执行的 ! 就算有多个 cpu 也不例外 !
synchronized 办法应用了类 java 的内置锁, 即锁住的是办法所属对象自身. 同一个锁某个时刻只能被一个执行线程所获取, 因而其余线程都得期待锁的开释.
因而就算你有多余的 cpu 能够执行, 然而你没有锁, 所以你还是不能进入 synchronized 办法执行, CPU 因而而闲暇.
如果某个线程长期持有一个竞争强烈的锁, 那么将导致其余线程都因期待所的开释而被挂起, 从而导致 CPU 无奈失去利用, 零碎吞吐量低下. 因而要尽量避免某个线程对锁的长期占有 !

验证代码

public class SyncMethod {public synchronized void syncMethod2() {
        try {System.out.println("@@@@@@@@@@@@@@@@@@@@@@@@ (syncMethod2, 曾经获取内置锁 `SyncMethod.this`)");
            Thread.sleep(5000);
        } catch (InterruptedException e) {e.printStackTrace();
        }
        System.out.println("@@@@@@@@@@@@@@@@@@@@@@@@ (syncMethod2, 行将开释内置锁 `SyncMethod.this`)");
    }
 
    public synchronized void syncMethod1() {System.out.println("######################## (syncMethod1, 曾经获取内置锁 `SyncMethod.this`, 并行将退出)");
    }
 
 
    static class Thread1 extends Thread {
        SyncMethod syncMethod;
 
        public Thread1(SyncMethod syncMethod) {this.syncMethod = syncMethod;}
 
        @Override
        public void run() {syncMethod.syncMethod2();
        }
    }
 
    static class Thread2 extends Thread {
        SyncMethod syncMethod;
 
        public Thread2(SyncMethod syncMethod) {this.syncMethod = syncMethod;}
 
        @Override
        public void run() {System.out.println("Thread2 running ...");
            syncMethod.syncMethod1();}
    }
 
    public static void main(String[] args) throws InterruptedException {SyncMethod syncMethod = new SyncMethod();
        Thread1 thread1 = new Thread1(syncMethod);
        Thread2 thread2 = new Thread2(syncMethod);
 
        thread1.start();    // 先执行, 以便抢占锁
        Thread.sleep(500); // 放弃 cpu, 让 thread1 执行, 以便获的锁
 
        thread2.start(); // 在 syncMethod1()办法取得锁时, 看看 syncMethod2()办法是否执行
 
        /*
        是否并发执行同一个对象不同的 synchronized 办法, 即看看是否同时进入一个对象 synchronized 办法块
        1. 创立一个有两个 synchronized 办法的对象 `syncMethod`
        2. 先启动一个线程 (Thread1), 并让其进入 syncMethod 对象的 sychronized 办法(syncMethod1) 内, 并使其停在 synchronized 办法内
        3. 再启动一个线程(Thread2), 并执行 syncMethod 对象的一个 synchronized 办法(syncMethod2), 看看是否进入此办法内
        输入如下: 
        @@@@@@@@@@@@@@@@@@@@@@@@ (syncMethod2, 曾经获取内置锁 `SyncMethod.this`)
        Thread2 running ...
        @@@@@@@@@@@@@@@@@@@@@@@@ (syncMethod2, 行将开释内置锁 `SyncMethod.this`)
        ######################## (syncMethod1, 曾经获取内置锁 `SyncMethod.this`, 并行将退出)
        后果剖析: 
            察看显示, 在输入 `Thread2 running ...` 后会暂停数秒(Thread2 无奈取得所而被挂起, 因为锁曾经被 Thread1 持有).
            如果不同线程能够同时拜访同一个对象不同 synchronized 办法的话, 
            在有足够 cpu 工夫片时(Thread1 在调用 syncMethod1 时应用 Thread.sleep 放弃了 cpu), 
            Thread2 调用的 syncMethod2 办法应该马上执行, 也就是 syncMethod2 办法中的语句在 `Thread2 running ...` 语句输入后马上输入, 
            而不是期待数秒才输入 (应为此时没有其余线程跟 Thread2 竞争 cpu, 况且当初的电脑都不只一个 cpu), 
            因而得出结论: "不同线程不能同时执行一个对象的不同 synchronized 办法"
            其实此论断是不言而喻的, 原理后面曾经说明, 此处不再赘述.
        */
 
    }
}

上面是一些对于应用锁的一些倡议:

①为了防止对锁的竞争, 你能够应用锁合成, 锁分段以及缩小线程持有锁的工夫

②如果上诉程序中的 syncMethod1 和 syncMethod2 办法是两个不相干的办法(申请的资源不存在关系),那么这两个办法能够别离应用两个不同的锁,革新之后 Thread1 和 Thread2 就不会产生因为锁竞争而挂起的状况了。革新后的 SyncMethod 类如下:

锁定两个不同的 Object 对象(lock1、lock2)

public class SyncMethod {private Object lock1 = new Object();
    private Object lock2 = new Object();
 
    public void syncMethod2() {synchronized (lock1) {
            try {System.out.println("@@@@@@@@@@@@@@@@@@@@@@@@ (syncMethod2, 曾经获取内置锁 `SyncMethod.this`)");
                Thread.sleep(5000);
            } catch (InterruptedException e) {e.printStackTrace();
            }
            System.out.println("@@@@@@@@@@@@@@@@@@@@@@@@ (syncMethod2, 行将开释内置锁 `SyncMethod.this`)");
        }
    }
 
    public void syncMethod1() {synchronized (lock2) {System.out.println("######################## (syncMethod1, 曾经获取内置锁 `SyncMethod.this`, 并行将退出)");
        }
    }
}

当然, 如果 syncMethod1 中耗时操作与锁定的资源无关, 那么也能够将耗时操作移出同步块. 在上述革新的根底上对 syncMethod1 的进一步革新如下:

public void syncMethod2() {synchronized (lock1) {System.out.println("@@@@@@@@@@@@@@@@@@@@@@@@ (syncMethod2, 曾经获取内置锁 `SyncMethod.this`)");
        System.out.println("@@@@@@@@@@@@@@@@@@@@@@@@ (syncMethod2, 行将开释内置锁 `SyncMethod.this`)");
    }
 
 
    // 将耗时操作移出同步块
    try {Thread.sleep(5000);// 与同步应用的资源无关的耗时操作
    } catch (InterruptedException e) {e.printStackTrace();
    }
}
退出移动版