synchronized ---锁

对象锁

synchronized修饰非静态方法

测试1:

     public class Run {
        public static void main(String[] args) {
            HasSelfPrivateNum numRef = new HasSelfPrivateNum();
            ThreadA athread = new ThreadA(numRef);
            athread.start();
    
            ThreadB bthread = new ThreadB(numRef);
            bthread.start();
    
        }}
    class HasSelfPrivateNum {
        private int num = 0;
        public void addI(String username) {
            try {
                if (username.equals("a")) {
                    num = 100;
                    System.out.println("a set over!");
                    Thread.sleep(2000);
                } else {
                    num = 200;
                    System.out.println("b set over!");
                }
                System.out.println(username + " num=" + num);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
    
    class ThreadA extends Thread {
        private HasSelfPrivateNum numRef;
        public ThreadA(HasSelfPrivateNum numRef) {
            super();
            this.numRef = numRef;
        }
    
        @Override
        public void run() {
            super.run();
            numRef.addI("a");
        }
    }
    
    class ThreadB extends Thread {
        private HasSelfPrivateNum numRef;
        public ThreadB(HasSelfPrivateNum numRef) {
            super();
            this.numRef = numRef;
        }
    
        @Override
        public void run() {
            super.run();
            numRef.addI("b");
        }
    }

运行结果为:

        a set over!
        b set over!
        b num=200
        a num=200

修改HasSelfPrivateNum如下,方法用synchronized修饰如下:

    class HasSelfPrivateNum {
        private int num = 0;
        synchronized public void addI(String username) {
            try {
                if (username.equals("a")) {
                    num = 100;
                    System.out.println("a set over!");
                    Thread.sleep(2000);
                } else {
                    num = 200;
                    System.out.println("b set over!");
                }
                System.out.println(username + " num=" + num);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

运行结果是线程安全的:

        b set over!
        b num=200
        a set over!
        a num=100
    
        接着,我在main方法中做了修改,让2个线程对象的入参不再是同一个HasSelfPrivateNum对象,即

运行结果为:

修改HasSelfPrivateNum如下,方法用synchronized修饰如下:

运行结果是线程安全的:

接着,我在main方法中做了修改,让2个线程对象的入参不再是同一个HasSelfPrivateNum对象,即

测试2:

     public static void main(String[] args) {
     
            HasSelfPrivateNum numRef = new HasSelfPrivateNum();
            HasSelfPrivateNum numRef2 = new HasSelfPrivateNum();
            ThreadA athread = new ThreadA(numRef);
            athread.start();
            ThreadB bthread = new ThreadB(numRef2);
            bthread.start();
     
        }
     

结果是

    a set over!
    b set over!
    b num=200
    a num=100

原因是:因为线程athread获得是numRef1的对象锁,而bthread线程获取的是numRef2的对象锁,他们并没有在获取锁上有竞争关系,因此,出现非同步的结果

接下来--

猜测A,它锁定了同一个对象,让这个对象在同一个时间只能在一个线程中使用,而其他的线程要等该对象被释放后,才等调用该变量?

猜测B:他仅仅限制了其他线程中这个对象调用与之相同的syncronized修饰的方法的权利?

猜测C:他仅仅限制了其他线程中这个对象调用syncronized修饰的方法的权利?

测试:在测试1的基础上 HasSelfPrivateNum类加入

      public void addI2(String username) {
            try {
                if (username.equals("a")) {
                    num = 100;
                    System.out.println("a set over!");
                    Thread.sleep(4000);
                } else {
                    num = 200;
                    System.out.println("b set over!");
                }
                System.out.println(username + " num=" + num);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

修改threadB

     class ThreadB extends Thread {
     
        private HasSelfPrivateNum numRef;
     
        public ThreadB(HasSelfPrivateNum numRef) {
            super();
            this.numRef = numRef;
        }
     
        @Override
        public void run() {
            super.run();
           // numRef.addI("b");
            numRef.addI2("b");  //调用了addI2
        }
     
    }

结果是:

    a set over!
    b set over!
    b num=200
    a num=200

接着又在addI2上加上syncronized

结果是:

    a set over!
    a num=100
    b set over!
    b num=200

结论是:他仅仅限制了其他线程中这个对象调用syncronized修饰的方法的权利.

实验结论:

在方法上加syncronized,那当有一个线程运行一个对象的syncronized修饰的方法时,其他的线程无法运行该对象的syncronized修饰的方法,只要该线程对该对象的使用完毕时,其他线程才能使用该对象的yncronized修饰的方法;注意:是可以运行该对象那些没有被syncronized修饰的方法的 



synchronized (this)

我们先看看代码实例(Run.java)

    package com.demo.syncronyzed;
    
    public class Run2 {
    
        public static void main(String[] args) {
            ObjectService service = new ObjectService();
         
            Thread1 a = new Thread1(service);
            a.setName("a");
            a.start();
         
            Thread2 b = new Thread2(service);
            b.setName("b");
            b.start();
        }
    
    }
    
    class ObjectService {
    
        public void serviceMethod() {
            try {
                synchronized (this) {
                    System.out.println("begin time=" + System.currentTimeMillis());
                    Thread.sleep(2000);
                    System.out.println("end    end=" + System.currentTimeMillis());
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
    }
    
    class Thread1 extends Thread {
    
        private ObjectService service;
    
        public Thread1(ObjectService service) {
            super();
            this.service = service;
        }
         
        @Override
        public void run() {
            super.run();
            service.serviceMethod();
        }
    
    }
    
    
    class Thread2 extends Thread {
    
        private ObjectService service;
    
        public Thread2(ObjectService service) {
            super();
            this.service = service;
        }
         
        @Override
        public void run() {
            super.run();
            service.serviceMethod();
        }
    
    }



运行结果:

这样也是同步的,线程获取的是同步块synchronized (this)括号()里面的对象实例的对象锁,这里就是ObjectService实例对象的对象锁了。

修改了

    class ObjectService {
    
        public void serviceMethod() {
            try {
                System.out.println("我是在同步代码块之前的,执行我的线程是"+Thread.currentThread().getName());
                synchronized (this) {
                    System.out.println( Thread.currentThread().getName()+":   begin time=" + System.currentTimeMillis());
                    Thread.sleep(4000);
                    System.out.println(Thread.currentThread().getName()+":   end    end=" + System.currentTimeMillis());
                }
                System.out.println("我是在同步代码块之后的,执行我的线程是"+Thread.currentThread().getName());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
    }

结果是

我是在同步代码块之前的,执行我的线程是a

a:   begin time=1520872280701

我是在同步代码块之前的,执行我的线程是b

a:   end    end=1520872284702

我是在同步代码块之后的,执行我的线程是a

b:   begin time=1520872284702

b:   end    end=1520872288703

我是在同步代码块之后的,执行我的线程是b

结论是:

synchronized (){}的{}前后的代码依旧是异步的 

class ObjectService加入了

        public void serviceMethod2() {
            try {
                synchronized (this) {
                    System.out.println( Thread.currentThread().getName()+":   begin time=" + System.currentTimeMillis());
                    Thread.sleep(4000);
                    System.out.println(Thread.currentThread().getName()+":   end    end=" + System.currentTimeMillis());
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

class Thread2 修改

    public void run() {
            super.run();
            //service.serviceMethod();
            service.serviceMethod2();
    
        }

结果是:

    a:   begin time=1520872632945
    a:   end    end=1520872636946
    b:   begin time=1520872636946
    b:   end    end=1520872640947

接着将上面加入方法的 synchronized (this)去掉

结果是

    a:   begin time=1520872837388
    b:   begin time=1520872837388
    a:   end    end=1520872841388
    b:   end    end=1520872841388

总结

synchronized (this),当有一个线程运行一个对象的synchronized (this)修饰的代码块时,其他的线程无法运行该对象的synchronized (this)修饰的代码块,只有该线程对该代码块的运行完毕时,其他线程才能使用该对象的synchronized (this)修饰的代码块;注意:是可以运行该对象那些没有被synchronized (this)的代码块的,synchronized (){}的{}前后的代码依旧是异步的

synchronized (非this对象)

    package com.demo.syncronyzed;
    
    public class Run {
     
        public static void main(String[] args) {
     
            Service service = new Service("程序员");
     
            ThreadA a = new ThreadA(service);
            a.setName("A");
            a.start();
     
            ThreadB b = new ThreadB(service);
            b.setName("B");
            b.start();
     
        }
     
    }
     
    class Service {
     
        String anyString = new String();
     
        public Service(String anyString){
            this.anyString = anyString;
        }
     
        public void setUsernamePassword(String username, String password) {
            try {
                synchronized (anyString) {
                    System.out.println("线程名称为:" + Thread.currentThread().getName()
                            + "在" + System.currentTimeMillis() + "进入同步块");
                    Thread.sleep(3000);
                    System.out.println("线程名称为:" + Thread.currentThread().getName()
                            + "在" + System.currentTimeMillis() + "离开同步块");
                }
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
     
    }
     
    class ThreadA extends Thread {
        private Service service;
     
        public ThreadA(Service service) {
            super();
            this.service = service;
        }
     
        @Override
        public void run() {
            service.setUsernamePassword("a", "aa");
     
        }
     
    }
     
    class ThreadB extends Thread {
     
        private Service service;
     
        public ThreadB(Service service) {
            super();
            this.service = service;
        }
     
        @Override
        public void run() {
            service.setUsernamePassword("b", "bb");
     
        }
     
    }

结果:

    线程名称为:A在1520873855721进入同步块
    
    线程名称为:A在1520873858723离开同步块
    
    线程名称为:B在1520873858723进入同步块
    
    线程名称为:B在1520873861723离开同步块

不难看出,这里线程争夺的是anyString的对象锁,两个线程有竞争同一对象锁的关系,出现同步



类锁

synchronized修饰静态方法

    package com.demo.syncronyzed;
    
    public class Run {
     
        public static void main(String[] args) {
     
            ThreadA a = new ThreadA();
            a.setName("A");
            a.start();
     
            ThreadB b = new ThreadB();
            b.setName("B");
            b.start();
     
        }
     
    }
     
    class Service {
     
        synchronized public static void printA() {
            try {
                System.out.println("线程名称为:" + Thread.currentThread().getName()
                        + "在" + System.currentTimeMillis() + "进入printA");
                Thread.sleep(3000);
                System.out.println("线程名称为:" + Thread.currentThread().getName()
                        + "在" + System.currentTimeMillis() + "离开printA");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
     
        synchronized public static void printB() {
            System.out.println("线程名称为:" + Thread.currentThread().getName() + "在"
                    + System.currentTimeMillis() + "进入printB");
            System.out.println("线程名称为:" + Thread.currentThread().getName() + "在"
                    + System.currentTimeMillis() + "离开printB");
        }
     
    }
     
    class ThreadA extends Thread {
        @Override
        public void run() {
            Service.printA();
        }
     
    }
     
    class ThreadB extends Thread {
        @Override
        public void run() {
            Service.printB();
        }
    }

结果

    线程名称为:A在1520874448288进入printA
    线程名称为:A在1520874451288离开printA
    线程名称为:B在1520874451288进入printB
    线程名称为:B在1520874451288离开printB

两个线程在争夺同一个类锁,因此同步,类锁方式与sycronized修饰方法,不同是,它修饰的是静态方法;当线程执行被sycrinized修饰的静态方法时,其他的线程如果也要sycrinized修饰的静态方法执行,就需要等待.可以运行该对象那些没有被**syncronized修饰的方法的**.这和sycronized修饰方法类似;

synchronized (类名.class)

    package com.demo.syncronyzed;
    
    
    public class Run {
    
        public static void main(String[] args) {
    
            ThreadA a = new ThreadA();
            a.setName("A");
            a.start();
    
            ThreadB b = new ThreadB();
            b.setName("B");
            b.start();
    
        }
    
    }
    class Service {
     
        public static void printA() {
            synchronized (Service.class) {
                try {
                    System.out.println("线程名称为:" + Thread.currentThread().getName()
                            + "在" + System.currentTimeMillis() + "进入printA");
                    Thread.sleep(3000);
                    System.out.println("线程名称为:" + Thread.currentThread().getName()
                            + "在" + System.currentTimeMillis() + "离开printA");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
     
        }
     
        public static void printB() {
            synchronized (Service.class) {
                System.out.println("线程名称为:" + Thread.currentThread().getName()
                        + "在" + System.currentTimeMillis() + "进入printB");
                System.out.println("线程名称为:" + Thread.currentThread().getName()
                        + "在" + System.currentTimeMillis() + "离开printB");
            }
        }
    }
    class ThreadA extends Thread {
        @Override
        public void run() {
            Service.printA();
        }
    
    }
    
    class ThreadB extends Thread {
        @Override
        public void run() {
            Service.printB();
        }
    }

结果是:

    线程名称为:A在1520875240022进入printA
    线程名称为:A在1520875243022离开printA
    线程名称为:B在1520875243022进入printB
    线程名称为:B在1520875243022离开printB

两个线程依旧在争夺同一个类锁,因此同步



加一个

        public  void printC() {
            synchronized (this) {
                System.out.println("线程名称为:" + Thread.currentThread().getName()
                        + "在" + System.currentTimeMillis() + "进入printB");
                System.out.println("线程名称为:" + Thread.currentThread().getName()
                        + "在" + System.currentTimeMillis() + "离开printB");
            }
        }

修改一下ThreadB

    class ThreadB extends Thread {
        @Override
        public void run() {
            Service service=new Service();
            service.printC();
        }

结果是:

    线程名称为:A在1520875593894进入printA
    线程名称为:B在1520875593894进入printB
    线程名称为:B在1520875593894离开printB
    线程名称为:A在1520875596894离开printA

说明了:

对于同一个类A,线程1争夺A对象实例的对象锁,线程2争夺类A的类锁,这两者不存在竞争关系。也就说对象锁和类锁互补干预内政;


猜你喜欢

转载自blog.csdn.net/weiqiang_java/article/details/79534862