2.1.4synchronized方法与锁对象

Posted 成功的路上总是离不开贵人的帮助,名师的指点和小人的刺激。

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2.1.4synchronized方法与锁对象相关的知识,希望对你有一定的参考价值。

为了证明线程锁的是对象

测试

 1 package com.cky.bean;
 2 
 3 /**
 4  * Created by chenkaiyang on 2017/12/4.
 5  */
 6 public class MyObject {
 7     public void methodA () {
 8         try {
 9             System.out.println("begin methodA ThName=" +Thread.currentThread().getName());
10             Thread.sleep(5000);
11             System.out.println("end");
12         } catch (InterruptedException e) {
13             e.printStackTrace();
14         }
15     }
16 }
 1 package com.cky.thread;
 2 
 3 import com.cky.bean.MyObject;
 4 
 5 /**
 6  * Created by chenkaiyang on 2017/12/4.
 7  */
 8 public class ThreadA  extends Thread{
 9     private MyObject mo;
10     public ThreadA (MyObject mo) {
11         this.mo = mo;
12     }
13     @Override
14     public void run() {
15         super.run();
16         mo.methodA();
17     }
18 }
package com.cky.thread;

import com.cky.bean.MyObject;

/**
 * Created by chenkaiyang on 2017/12/4.
 */
public class ThreadB extends Thread{
    private MyObject mo;
    public ThreadB (MyObject mo) {
        this.mo = mo;
    }
    @Override
    public void run() {
        super.run();
        mo.methodA();
    }
}
package com.cky.test;

import com.cky.bean.MyObject;
import com.cky.thread.ThreadA;
import com.cky.thread.ThreadB;

/**
 * Created by chenkaiyang on 2017/12/2.
 */
public class Test {
    public static void main(String[] args){
        MyObject myObject = new MyObject();
        ThreadA threadA = new ThreadA(myObject);
        threadA.setName("A");
        ThreadB threadB = new ThreadB(myObject);
        threadB.setName("B");
        threadA.start();
        threadB.start();
    }
}
D:\it\jdk1.8\bin\java -Didea.launcher.port=7533 "-Didea.launcher.bin.path=D:\it\idea\IntelliJ IDEA 2016.3.3\bin" -Dfile.encoding=UTF-8 -classpath "D:\it\jdk1.8\jre\lib\charsets.jar;D:\it\jdk1.8\jre\lib\deploy.jar;D:\it\jdk1.8\jre\lib\ext\access-bridge-64.jar;D:\it\jdk1.8\jre\lib\ext\cldrdata.jar;D:\it\jdk1.8\jre\lib\ext\dnsns.jar;D:\it\jdk1.8\jre\lib\ext\jaccess.jar;D:\it\jdk1.8\jre\lib\ext\jfxrt.jar;D:\it\jdk1.8\jre\lib\ext\localedata.jar;D:\it\jdk1.8\jre\lib\ext\nashorn.jar;D:\it\jdk1.8\jre\lib\ext\sunec.jar;D:\it\jdk1.8\jre\lib\ext\sunjce_provider.jar;D:\it\jdk1.8\jre\lib\ext\sunmscapi.jar;D:\it\jdk1.8\jre\lib\ext\sunpkcs11.jar;D:\it\jdk1.8\jre\lib\ext\zipfs.jar;D:\it\jdk1.8\jre\lib\javaws.jar;D:\it\jdk1.8\jre\lib\jce.jar;D:\it\jdk1.8\jre\lib\jfr.jar;D:\it\jdk1.8\jre\lib\jfxswt.jar;D:\it\jdk1.8\jre\lib\jsse.jar;D:\it\jdk1.8\jre\lib\management-agent.jar;D:\it\jdk1.8\jre\lib\plugin.jar;D:\it\jdk1.8\jre\lib\resources.jar;D:\it\jdk1.8\jre\lib\rt.jar;F:\springboot\threaddemo\out\production\threaddemo;D:\it\idea\IntelliJ IDEA 2016.3.3\lib\idea_rt.jar" com.intellij.rt.execution.application.AppMain com.cky.test.Test
begin methodA ThName=A
begin methodA ThName=B
end
end

结果如上分析,代码调用是异步随机执行。

然后在方法中加同步关键字

package com.cky.bean;

/**
 * Created by chenkaiyang on 2017/12/4.
 */
public class MyObject {
    synchronized  public void methodA () {
        try {
            System.out.println("begin methodA ThName=" +Thread.currentThread().getName());
            Thread.sleep(5000);
            System.out.println("end");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
D:\it\jdk1.8\bin\java -Didea.launcher.port=7534 "-Didea.launcher.bin.path=D:\it\idea\IntelliJ IDEA 2016.3.3\bin" -Dfile.encoding=UTF-8 -classpath "D:\it\jdk1.8\jre\lib\charsets.jar;D:\it\jdk1.8\jre\lib\deploy.jar;D:\it\jdk1.8\jre\lib\ext\access-bridge-64.jar;D:\it\jdk1.8\jre\lib\ext\cldrdata.jar;D:\it\jdk1.8\jre\lib\ext\dnsns.jar;D:\it\jdk1.8\jre\lib\ext\jaccess.jar;D:\it\jdk1.8\jre\lib\ext\jfxrt.jar;D:\it\jdk1.8\jre\lib\ext\localedata.jar;D:\it\jdk1.8\jre\lib\ext\nashorn.jar;D:\it\jdk1.8\jre\lib\ext\sunec.jar;D:\it\jdk1.8\jre\lib\ext\sunjce_provider.jar;D:\it\jdk1.8\jre\lib\ext\sunmscapi.jar;D:\it\jdk1.8\jre\lib\ext\sunpkcs11.jar;D:\it\jdk1.8\jre\lib\ext\zipfs.jar;D:\it\jdk1.8\jre\lib\javaws.jar;D:\it\jdk1.8\jre\lib\jce.jar;D:\it\jdk1.8\jre\lib\jfr.jar;D:\it\jdk1.8\jre\lib\jfxswt.jar;D:\it\jdk1.8\jre\lib\jsse.jar;D:\it\jdk1.8\jre\lib\management-agent.jar;D:\it\jdk1.8\jre\lib\plugin.jar;D:\it\jdk1.8\jre\lib\resources.jar;D:\it\jdk1.8\jre\lib\rt.jar;F:\springboot\threaddemo\out\production\threaddemo;D:\it\idea\IntelliJ IDEA 2016.3.3\lib\idea_rt.jar" com.intellij.rt.execution.application.AppMain com.cky.test.Test
begin methodA ThName=A
end
begin methodA ThName=B
end

结果分析:

调用关键字synchronized声明的方法一定是排队运行的,只有共享的资源才需要同步,如果不是共享的资源,根本没有必要同步。

那如果其他的方法被调用会有什么效果。

测试

继续更改MyObject

package com.cky.bean;

/**
 * Created by chenkaiyang on 2017/12/4.
 */
public class MyObject {
    synchronized  public void methodA () {
        try {
            System.out.println("begin methodA ThName=" +Thread.currentThread().getName());
            Thread.sleep(5000);
            System.out.println("end");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    public void methodB() {
        try {
            System.out.println("begin methodB ThName=" +Thread.currentThread().getName());
            Thread.sleep(5000);
            System.out.println("end");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
package com.cky.thread;

import com.cky.bean.MyObject;

/**
 * Created by chenkaiyang on 2017/12/4.
 */
public class ThreadA  extends Thread{
    private MyObject mo;
    public ThreadA (MyObject mo) {
        this.mo = mo;
    }
    @Override
    public void run() {
        super.run();
        mo.methodA();
    }
}
package com.cky.thread;

import com.cky.bean.MyObject;

/**
 * Created by chenkaiyang on 2017/12/4.
 */
public class ThreadB extends Thread{
    private MyObject mo;
    public ThreadB (MyObject mo) {
        this.mo = mo;
    }
    @Override
    public void run() {
        super.run();
        mo.methodB();
    }
}
package com.cky.test;

import com.cky.bean.MyObject;
import com.cky.thread.ThreadA;
import com.cky.thread.ThreadB;

/**
 * Created by chenkaiyang on 2017/12/2.
 */
public class Test {
    public static void main(String[] args){
        MyObject myObject = new MyObject();
        ThreadA threadA = new ThreadA(myObject);
        threadA.setName("A");
        ThreadB threadB = new ThreadB(myObject);
        threadB.setName("B");
        threadA.start();
        threadB.start();
    }
}
D:\it\jdk1.8\bin\java -Didea.launcher.port=7536 "-Didea.launcher.bin.path=D:\it\idea\IntelliJ IDEA 2016.3.3\bin" -Dfile.encoding=UTF-8 -classpath "D:\it\jdk1.8\jre\lib\charsets.jar;D:\it\jdk1.8\jre\lib\deploy.jar;D:\it\jdk1.8\jre\lib\ext\access-bridge-64.jar;D:\it\jdk1.8\jre\lib\ext\cldrdata.jar;D:\it\jdk1.8\jre\lib\ext\dnsns.jar;D:\it\jdk1.8\jre\lib\ext\jaccess.jar;D:\it\jdk1.8\jre\lib\ext\jfxrt.jar;D:\it\jdk1.8\jre\lib\ext\localedata.jar;D:\it\jdk1.8\jre\lib\ext\nashorn.jar;D:\it\jdk1.8\jre\lib\ext\sunec.jar;D:\it\jdk1.8\jre\lib\ext\sunjce_provider.jar;D:\it\jdk1.8\jre\lib\ext\sunmscapi.jar;D:\it\jdk1.8\jre\lib\ext\sunpkcs11.jar;D:\it\jdk1.8\jre\lib\ext\zipfs.jar;D:\it\jdk1.8\jre\lib\javaws.jar;D:\it\jdk1.8\jre\lib\jce.jar;D:\it\jdk1.8\jre\lib\jfr.jar;D:\it\jdk1.8\jre\lib\jfxswt.jar;D:\it\jdk1.8\jre\lib\jsse.jar;D:\it\jdk1.8\jre\lib\management-agent.jar;D:\it\jdk1.8\jre\lib\plugin.jar;D:\it\jdk1.8\jre\lib\resources.jar;D:\it\jdk1.8\jre\lib\rt.jar;F:\springboot\threaddemo\out\production\threaddemo;D:\it\idea\IntelliJ IDEA 2016.3.3\lib\idea_rt.jar" com.intellij.rt.execution.application.AppMain com.cky.test.Test
begin methodA ThName=A
begin methodB ThName=B
end
end

结果分析:虽然线程A先持有object对象的锁,但是线程B完全可以异步调用非synchronized类型的方法。

继续再methodB方法上加上synchronized

package com.cky.bean;

/**
 * Created by chenkaiyang on 2017/12/4.
 */
public class MyObject {
    synchronized  public void methodA () {
        try {
            System.out.println("begin methodA ThName=" +Thread.currentThread().getName());
            Thread.sleep(5000);
            System.out.println("end");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
   synchronized public void methodB() {
        try {
            System.out.println("begin methodB ThName=" +Thread.currentThread().getName());
            Thread.sleep(5000);
            System.out.println("end");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
D:\it\jdk1.8\bin\java -Didea.launcher.port=7537 "-Didea.launcher.bin.path=D:\it\idea\IntelliJ IDEA 2016.3.3\bin" -Dfile.encoding=UTF-8 -classpath "D:\it\jdk1.8\jre\lib\charsets.jar;D:\it\jdk1.8\jre\lib\deploy.jar;D:\it\jdk1.8\jre\lib\ext\access-bridge-64.jar;D:\it\jdk1.8\jre\lib\ext\cldrdata.jar;D:\it\jdk1.8\jre\lib\ext\dnsns.jar;D:\it\jdk1.8\jre\lib\ext\jaccess.jar;D:\it\jdk1.8\jre\lib\ext\jfxrt.jar;D:\it\jdk1.8\jre\lib\ext\localedata.jar;D:\it\jdk1.8\jre\lib\ext\nashorn.jar;D:\it\jdk1.8\jre\lib\ext\sunec.jar;D:\it\jdk1.8\jre\lib\ext\sunjce_provider.jar;D:\it\jdk1.8\jre\lib\ext\sunmscapi.jar;D:\it\jdk1.8\jre\lib\ext\sunpkcs11.jar;D:\it\jdk1.8\jre\lib\ext\zipfs.jar;D:\it\jdk1.8\jre\lib\javaws.jar;D:\it\jdk1.8\jre\lib\jce.jar;D:\it\jdk1.8\jre\lib\jfr.jar;D:\it\jdk1.8\jre\lib\jfxswt.jar;D:\it\jdk1.8\jre\lib\jsse.jar;D:\it\jdk1.8\jre\lib\management-agent.jar;D:\it\jdk1.8\jre\lib\plugin.jar;D:\it\jdk1.8\jre\lib\resources.jar;D:\it\jdk1.8\jre\lib\rt.jar;F:\springboot\threaddemo\out\production\threaddemo;D:\it\idea\IntelliJ IDEA 2016.3.3\lib\idea_rt.jar" com.intellij.rt.execution.application.AppMain com.cky.test.Test
begin methodB ThName=B
end
begin methodA ThName=A
end

Process finished with exit code 0

结果分析:

1)A线程先持有对象锁,B线程可以异步方法调用object对象中非同步的方法

2)A线程先持有对象锁,B线程此时如果想要调用B线程中其他的同步方法,则需要等待A线程释放才行

以上是关于2.1.4synchronized方法与锁对象的主要内容,如果未能解决你的问题,请参考以下文章

Java线程:线程的同步与锁

Java多线程---同步与锁

原子性与锁

并发编程:锁重入与锁异常

事务与锁当Transactional遇上synchronized

Java多线程编程对象及变量的并发访问