美文网首页
多线程系列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