美文网首页
多线程系列04-Syncronized关键字

多线程系列04-Syncronized关键字

作者: Sandy_678f | 来源:发表于2019-07-18 17:12 被阅读0次

Java中,每个对象有且只有一个同步锁。调用对象的synchronized方法时,就获取了该对象的同步锁。
Java中一共有两种类型的锁
Java类锁(全局锁):类锁是用synchronized修饰类的静态方法或者一个类的class对象(一个类只有一个.class对象)
Java对象锁(实例锁):对象锁用synchronize修饰普通方法或者代码块
不同线程对锁的访问是互斥的。

synchronized的基本规则:
规则一. 当一个线程访问“某对象”的“synchronized方法”或者“synchronized代码块”时,其他线程对“该对象”的该“synchronized方法”或者“synchronized代码块”的访问将被阻塞。
示例:

public class MyRunnable implements Runnable{
    @Override
    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();
            }
        }
    }

    public static void main(String[] args) {
        Runnable demo = new MyRunnable();

        Thread thread1 = new Thread(demo,"thread1");
        Thread thread2 = new Thread(demo,"thread2");
        thread2.start();
        thread1.start();
    }
}

运行结果:

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

结果说明:
thread1和thread2都是基于"demo这个Runnable对象"创建的线程。这就意味着,我们可以将synchronized(this)中的this看作是“demo这个Runnable对象”;因此,线程t1和t2共享“demo对象的同步锁”。

另一个例子:

public class MyThread extends Thread {

    public MyThread(String name){
        super(name);
    }

    @Override
    public void run() {
        //获取当前对象的同步锁
        synchronized (this){
            for(int i =0; i<5; i++){
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + " loop " + i);
            }
        }
    }

    public static void main(String[] args) {
        Thread thread1 = new MyThread("thread1");
        Thread thread2 = new MyThread("thread2");
        thread2.start();
        thread1.start();
    }
}

运行结果:

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

结果说明:
synchronized(this)中的this代表的是MyThread对象,而t1和t2是两个不同的MyThread对象,因此t1和t2在执行synchronized(this)时,获取的是不同对象的同步锁。

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

public class Count {

    public void synMethod(){
        synchronized(this) {
            try {
                for (int i = 0; i < 5; i++) {
                    Thread.sleep(100); // 休眠100ms
                    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); // 休眠100ms
                System.out.println(Thread.currentThread().getName() + " nonSynMethod loop " + i);
            }
        } catch (InterruptedException ie) {
        }
    }

    public static void main(String[] args) {
        final Count count = new Count();

        Thread t1 = new Thread(new Runnable() {
            public void run() {
                count.synMethod();
            }
        }, "t1");

        Thread t2 = new Thread(new Runnable() {
            public void run() {
                count.nonSynMethod();
                                count.synMethod();
            }
        }, "t2");

        t1.start();
        t2.start();
    }
}

运行结果:

t2 nonSynMethod loop 0
t1 synMethod loop 0
t1 synMethod loop 1
t2 nonSynMethod loop 1
t2 nonSynMethod loop 2
t1 synMethod loop 2
t2 nonSynMethod loop 3
t1 synMethod loop 3
t2 nonSynMethod loop 4
t1 synMethod loop 4
t2 synMethod loop 0
t2 synMethod loop 1
t2 synMethod loop 2
t2 synMethod loop 3
t2 synMethod loop 4

结果说明:t1,t2均访问的count对象,t1先获取到count对象的实例锁,t2先访问count的非同步代码块。等t1释放锁后,t2访问count对象的同步代码块。

规则三. 当一个线程访问“某对象”的“synchronized方法”或者“synchronized代码块”时,其他线程对“该对象”的其他的“synchronized方法”或者“synchronized代码块”的访问将被阻塞。
示例:

public class Count {

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

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

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

    public static void main(String[] args) {
        final Count count = new Count();

        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                count.synMethod1();
            }
        },"thread1");

        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                count.nonsynMethod();
            }
        },"thread2");

        Thread thread3 = new Thread(new Runnable() {
            @Override
            public void run() {
                count.synMethod2();
            }
        },"thread3");

        thread1.start();
        thread2.start();
        thread3.start();

    }
}

运行结果:

thread2 nonsynMethod loop 0
thread1 synMethod1 loop 0
thread2 nonsynMethod loop 1
thread1 synMethod1 loop 1
thread2 nonsynMethod loop 2
thread1 synMethod1 loop 2
thread2 nonsynMethod loop 3
thread1 synMethod1 loop 3
thread1 nonsynMethod loop 4
thread1 synMethod1 loop 4
thread2 nonsynMethod loop 5
thread3 synMethod2 loop 0
thread1 synMethod2 loop 1
thread3 synMethod2 loop 2
thread3 synMethod2 loop 3
thread3 synMethod2 loop 4
thread3 synMethod2 loop 5

结果说明:
thread1,thread1,thread3都是基于同一个count对象创建的线程。

关于全局锁和实例锁的一些说明:

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

(01) x.isSyncA()与x.isSyncB()
(02) x.isSyncA()与y.isSyncA()
(03) x.cSyncA()与y.cSyncB()
(04) x.isSyncA()与Something.cSyncA()

(01) 不能被同时访问。因为isSyncA()和isSyncB()都是访问同一个对象(对象x)的同步锁!

public class LockDemo {

    public synchronized void isSyncA() {
        try {
            for (int i=0;i<5;i++) {
                Thread.sleep(100);
                System.out.println(Thread.currentThread().getName() + " : isSyncA");
            }
        } catch (InterruptedException ie) {
        }
    }

    public synchronized void isSyncB(){
        try {
            for (int i=0;i<5;i++) {
                Thread.sleep(100);
                System.out.println(Thread.currentThread().getName() + " : isSyncB");
            }
        } catch (InterruptedException ie) {
        }
    }

    public static void main(String[] args) {

        final LockDemo lockDemo1 = new LockDemo();
        final LockDemo lockDemo2 = new LockDemo();

        Thread t11 = new Thread(new Runnable() {
            @Override
            public void run() {
                lockDemo1.isSyncA();
            }
        },"t11");

        Thread t12 = new Thread(new Runnable() {
            @Override
            public void run() {
                lockDemo1.isSyncB();
            }
        },"t12");

        t11.start();
        t12.start();
    }
}

运行结果:

t11 : isSyncA
t11 : isSyncA
t11 : isSyncA
t11 : isSyncA
t11 : isSyncA
t12 : isSyncB
t12 : isSyncB
t12 : isSyncB
t12 : isSyncB
t12 : isSyncB

结果说明:访问的均是lockDemo1对象的同步锁。

(02) 可以同时被访问

public class LockDemo {

    public synchronized void isSyncA() {
        try {
            for (int i=0;i<5;i++) {
                Thread.sleep(100);
                System.out.println(Thread.currentThread().getName() + " : isSyncA");
            }
        } catch (InterruptedException ie) {
        }
    }

    public synchronized void isSyncB(){
        try {
            for (int i=0;i<5;i++) {
                Thread.sleep(100);
                System.out.println(Thread.currentThread().getName() + " : isSyncB");
            }
        } catch (InterruptedException ie) {
        }
    }

    public static void main(String[] args) {

        final LockDemo lockDemo1 = new LockDemo();
        final LockDemo lockDemo2 = new LockDemo();

        Thread t11 = new Thread(new Runnable() {
            @Override
            public void run() {
                lockDemo1.isSyncA();
            }
        },"t11");

        Thread t12 = new Thread(new Runnable() {
            @Override
            public void run() {
                lockDemo2.isSyncB();
            }
        },"t12");

        t11.start();
        t12.start();
    }
}

运行结果:

t12 : isSyncB
t11 : isSyncA
t12 : isSyncB
t11 : isSyncA
t12 : isSyncB
t11 : isSyncA
t12 : isSyncB
t11 : isSyncA
t12 : isSyncB
t11 : isSyncA

结果说明:访问的是lockDemo1与lockDemo2两个对象的同步锁。

(03) 不能被同时访问。

public class LockDemo {

    public synchronized void isSyncA() {
        try {
            for (int i=0;i<5;i++) {
                Thread.sleep(100);
                System.out.println(Thread.currentThread().getName() + " : isSyncA");
            }
        } catch (InterruptedException ie) {
        }
    }

    public synchronized void isSyncB(){
        try {
            for (int i=0;i<5;i++) {
                Thread.sleep(100);
                System.out.println(Thread.currentThread().getName() + " : isSyncB");
            }
        } catch (InterruptedException ie) {
        }
    }

    public static synchronized void cSyncA(){
        try{
            for (int i=0;i<5;i++) {
                Thread.sleep(100);
                System.out.println(Thread.currentThread().getName() + " : csyncA");
            }
        } catch (InterruptedException ie) {
        }
    }

    public static synchronized void cSyncB(){
        try{
            for (int i=0;i<5;i++) {
                Thread.sleep(100);
                System.out.println(Thread.currentThread().getName() + " : csyncB");
            }
        } catch (InterruptedException ie) {
        }
    }

    public static void main(String[] args) {

        final LockDemo lockDemo1 = new LockDemo();
        final LockDemo lockDemo2 = new LockDemo();

        Thread t11 = new Thread(new Runnable() {
            @Override
            public void run() {
                lockDemo1.isSyncA();
            }
        },"t11");

        Thread t12 = new Thread(new Runnable() {
            @Override
            public void run() {
                lockDemo2.isSyncB();
            }
        },"t12");

        Thread t13 = new Thread(new Runnable() {
            @Override
            public void run() {
                LockDemo.cSyncA();
            }
        },"t13");

        Thread t14 = new Thread(new Runnable() {
            @Override
            public void run() {
                LockDemo.cSyncB();
            }
        },"t14");

//        t11.start();
//        t12.start();
        t13.start();
        t14.start();
    }
}

运行结果:

t13 : csyncA
t13 : csyncA
t13 : csyncA
t13 : csyncA
t13 : csyncA
t14 : csyncB
t14 : csyncB
t14 : csyncB
t14 : csyncB
t14 : csyncB

结果说明:访问的都是LockDemo的同步锁

(04) 可以被同时访问。
运行结果:

t13 : csyncA
t12 : isSyncB
t12 : isSyncB
t13 : csyncA
t13 : csyncA
t12 : isSyncB
t13 : csyncA
t12 : isSyncB
t13 : csyncA
t12 : isSyncB

结果说明:因为isSyncA()是实例方法,x.isSyncA()使用的是对象x的锁;而cSyncA()是静态方法,Something.cSyncA()可以理解对使用的是“类的锁”。因此,它们是可以被同时访问的。

相关文章

网友评论

      本文标题:多线程系列04-Syncronized关键字

      本文链接:https://www.haomeiwen.com/subject/hjnllctx.html