java基础之多线程(二)--Synchronized关键字

synchronized原理

  • java中一个对象有且仅有一个同步锁。同步锁依赖对象存在;
  • 调用对象的synchronized方法时,就获取了对象的同步锁;
  • 不同线程对同步锁的访问时互斥的;

sychronized基本规则

1、当一个线程访问“某对象”的“synchronized方法”或者“synchronized代码块”时,其他线程对“该对象”的该“synchronized方法”或者“synchronized代码块”的访问将被阻塞。

public class SynchronizedTest {
    public static void main(String[] args) {

        SameClassSameSynchronizedBlock thread = new SameClassSameSynchronizedBlock();

        Thread thread1 = new Thread(thread,"thread1");
        Thread thread2 = new Thread(thread,"thread2");

        thread1.start();
        thread2.start();
    }
}

/**
 * 1、已有线程调用类中同步代码块时,另一个线程调用同一个类的同一个同步代码块时,需要等待锁释放
 * 注意,若使用继承Thread类的方法来创建线程,在main中实例化两个Thread子类,在此处通过this获取到的同步锁属于两个不同对象,无法使得两个线程互斥
 * 若使用实现Runnable接口的方式创建线程,在main中只需实例化一个实现类,故this获取到的同步锁为同一个,可以达到使两个线程互斥的目的
 */
class SameClassSameSynchronizedBlock implements Runnable{
    public void run() {
        synchronized (this){
            try {
                for(int i = 0; i < 5; i++){
                    Thread.sleep(100);
                    System.out.println(Thread.currentThread().getName() + " loop " + i);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

运行结果:

thread1 loop 0
thread1 loop 1
thread1 loop 2
thread1 loop 3
thread1 loop 4
thread2 loop 0
thread2 loop 1
thread2 loop 2
thread2 loop 3
thread2 loop 4

2、当一个线程访问“某对象”的“synchronized方法”或者“synchronized代码块”时,其他线程仍然可以访问“该对象”的非同步代码块

public class SynchronizedTest {
    public static void main(String[] args) {
        final SameClassNonSynchronizedBlock sameClassNonSynchronizedBlock = new SameClassNonSynchronizedBlock();
        Thread thread3 = new Thread(new Runnable() {
            public void run() {
                sameClassNonSynchronizedBlock.synMethod();
            }
        }, "thread3");
        Thread thread4 = new Thread(new Runnable() {
            public void run() {
                sameClassNonSynchronizedBlock.nonSynMethod();
            }
        }, "thread4");

        thread3.start();
        thread4.start();
    }
}
/**
 * 2、已有线程调用类中同步代码块时,另一个线程调用同一个类的非同步代码块时,无需等待锁释放
 */
class SameClassNonSynchronizedBlock {

    // 含有synchronized同步块的方法
    public void synMethod() {
        synchronized (this) {
            try {
                for (int i = 0; i < 5; i++) {
                    Thread.sleep(100);
                    System.out.println(Thread.currentThread().getName() + " synMethod loop " + i);
                }
            } catch (InterruptedException ie) {
            }
        }
    }

    // 非同步的方法
    public void nonSynMethod() {
        try {
            for (int i = 0; i < 5; i++) {
                Thread.sleep(100);
                System.out.println(Thread.currentThread().getName() + " nonSynMethod loop " + i);
            }
        } catch (InterruptedException ie) {
        }
    }
}

运行结果:

thread4 nonSynMethod loop 0
thread3 synMethod loop 0
thread3 synMethod loop 1
thread4 nonSynMethod loop 1
thread3 synMethod loop 2
thread4 nonSynMethod loop 2
thread3 synMethod loop 3
thread4 nonSynMethod loop 3
thread3 synMethod loop 4
thread4 nonSynMethod loop 4

3、 当一个线程访问“某对象”的“synchronized方法”或者“synchronized代码块”时,其他线程对“该对象”的其他的“synchronized方法”或者“synchronized代码块”的访问将被阻塞。

public class SynchronizedTest {
    public static void main(String[] args) {
        final SameClassDiffSynchronizedMethod sameClassDiffSynchronizedMethod = new SameClassDiffSynchronizedMethod();

        Thread thread5 = new Thread(new Runnable() {
            public void run() {
                sameClassDiffSynchronizedMethod.synMethod1();
            }
        }, "thread5");
        Thread thread6 = new Thread(new Runnable() {
            public void run() {
                sameClassDiffSynchronizedMethod.synMethod2();
            }
        }, "thread6");

        thread5.start();
        thread6.start();
    }
}

class SameClassDiffSynchronizedMethod{
    //同步方法1
    public synchronized void synMethod1(){
        try {
            for (int i = 0; i < 5; i++) {
                Thread.sleep(100);
                System.out.println(Thread.currentThread().getName() + " synMethod1 loop " + i);
            }
        } catch (InterruptedException ie) {
        }
    }

    //同步方法2
    public synchronized void synMethod2(){
        try {
            for (int i = 0; i < 5; i++) {
                Thread.sleep(100);
                System.out.println(Thread.currentThread().getName() + " synMethod2 loop " + i);
            }
        } catch (InterruptedException ie) {
        }
    }
}

运行结果:

thread5 synMethod1 loop 0
thread5 synMethod1 loop 1
thread5 synMethod1 loop 2
thread5 synMethod1 loop 3
thread5 synMethod1 loop 4
thread6 synMethod2 loop 0
thread6 synMethod2 loop 1
thread6 synMethod2 loop 2
thread6 synMethod2 loop 3
thread6 synMethod2 loop 4

实例锁和全局锁

实例锁

锁在某一个实例对象上,若该类为单例对象,该锁具有全局性质。实例锁对应synchronized关键字。

全局锁

该锁针对的是类,无论实例多少个对象,那么线程都共享该锁。全局锁对应static synchronized(或者是锁在该类的class或者classloader对象上)

eg:

pulbic class Something {
    public synchronized void isSyncA(){}
    public synchronized void isSyncB(){}
    public static synchronized void cSyncA(){}
    public static synchronized void cSyncB(){}
}

假设,Something有两个实例x和y。分析下面4组表达式获取的锁的情况。
(01) x.isSyncA()与x.isSyncB()
(02) x.isSyncA()与y.isSyncA()
(03) x.cSyncA()与y.cSyncB()
(04) x.isSyncA()与Something.cSyncA()

  • (01) 不能被同时访问。因为isSyncA()和isSyncB()都是访问同一个对象(对象x)的同步锁!
  • (02) 可以同时被访问。因为访问的不是同一个对象的同步锁,x.isSyncA()访问的是x的同步锁,而y.isSyncA()访问的是y的同步锁。
  • (03) 不能被同时访问。因为cSyncA()和cSyncB()都是static类型,x.cSyncA()相当于Something.isSyncA(),y.cSyncB()相当于Something.isSyncB(),因此它们共用一个同步锁,不能被同时访问。
  • (04) 可以被同时访问。因为isSyncA()是实例方法,x.isSyncA()使用的是对象x的锁;而cSyncA()是静态方法,Something.cSyncA()可以理解对使用的是“类的锁”。因此,它们是可以被同时访问的。

猜你喜欢

转载自blog.csdn.net/yzy199391/article/details/81357082