Java synchronized 关键字使用方法

来源:互联网 发布:seo实战密码电子书 编辑:程序博客网 时间:2024/06/01 10:22

synchronized关键字,代表这个方法加锁,相当于不管哪一个线程(例如线程A),运行到这个方法时,都要检查有没有其它线程B(或者C、 D等)正在用这个方法(或者该类的其他同步方法),有的话要等正在使用synchronized方法的线程B(或者C 、D)运行完这个方法后再运行此线程A,没有的话,锁定调用者,然后直接运行。它包括两种用法:synchronized 方法和 synchronized 块。 —— [ 百度百科 ]

Java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码。

一、当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等 待当前线程执行完这个代码块以后才能执行该代码块。
二、然而,当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。
三、尤其关键的是,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。
四、第三个例子同样适用其它同步代码块。也就是说,当一个线程访问object的一个synchronized(this)同步代码块时,它就获得了这个object的对象锁。结果,其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。
五、以上规则对其它对象锁同样适用.


用于代码片段:synchronized (Class.class)

public class SyncClass {    public static void main(String[] args) {        final BeanB a = new BeanB();        //线程A        new Thread(a, "Thread--A").start();        //线程B        new Thread(a, "Thread--B").start();    }}class BeanB implements Runnable {    @Override    public void run() {        synchronized (BeanB.class) {            for (int i = 0; i < 5; i++) {                System.out.println(Thread.currentThread().getName() + ":" + i);            }        }    }}

说明:
在代码片段synchronized(),括号中的参数为Class时;(粗粒度锁,性能开销大),线程获得锁为类锁,该方式能正真实现该类的断面执行,这种方式不是针对该类某个实例对象,而是针对类而言,它只有唯一的类定义,也就是对于该类来说,只有一个线程能获得锁,不可以并行;

运行结果:
类同步代码运行结果

从运行结果可以看到,在两个线程中访问同一个实例,也不会出现交叉输出;一定是一个线程结束,另一个线程才开始执行;

用于代码片段:synchronized (Object obj)

public class PubSyncClass {    public static void main(String[] args) {        final BeanC ca= new BeanC();        final BeanC cb = new BeanC();        //线程A        new Thread(ca, "Thread--A").start();  //执行同一实例        //线程B        new Thread(ca, "Thread--B").start();  //执行同一实例        //线程C        new Thread(cb, "Thread--C").start();  //执行新的实例    }}class BeanC implements  Runnable{    //静态变量,线程共享;非静态变量,只对当前实例有同步效果,等同于方法前加synchronized效果,只是粒度不同    private static Object obj=new Object();    @Override    public void run(){        synchronized (obj){            for (int i = 0; i < 5; i++) {                System.out.println(Thread.currentThread().getName() + ":" + i);            }        }    }}

说明:
在代码片段synchronized(),括号中的参数为一个Object对象(对象锁);如果这个Object对象不是static的,那么此时锁只针对当前实例(等同于方法锁),要基于公共对象实现类锁,该Object对象必须是static的;同步一般原理是应该减少同步粒度,以达到更好的性能;这种方法比类锁,更加适用类的局部同步;

运行结果:
基于类成员进行类同步运行结果

从运行结果可以看到,在两个线程中访问同一个实例,或者在不同的线程中访问不同的实例都不会出现交叉输出;一定是一个线程结束,另一个线程才开始执行;

用于方法:public synchronized void methodName()

public class SyncMethod {    public static void main(String[] args) {        final BeanA a = new BeanA();        final BeanA b = new BeanA();        //线程A        new Thread(a, "Thread--A").start();  //执行同一实例个实例        //线程B        new Thread(a, "Thread--B").start();  //执行同一实例个实例        //线程C        new Thread(b, "Thread--C").start();  ////执行新的实例    }}class BeanA implements Runnable {    /**     * @Description 同步方法     * @Author jaood     * @Date 2017/7/27 15:49     * @Param []     * @Return void     */    @Override    public synchronized void run() {        for (int i = 0; i < 5; i++) {            System.out.println(Thread.currentThread().getName() + ":" + i);        }    }}

说明:
在非static方法前加synchronized,那么该方法对于当前实例是同步的(所以方法锁也是对象锁,只针对当前实例),在static修饰的方法前加synchronized,也可实现类锁;

运行结果:
方法同步运行结果
方法同步运行结果

从运行结果可以看到A和B一定是断面执行,而A和C、B和C是可以并行执行的;也就是说方法锁只针对当前实例,而新的实例仍可以执行该同步方法;在两个线程中访问不同的实例,不会出现交叉输出;但访问同一个实例,还是会出现并行执行;

用于代码片段:synchronized (this)

只针对当前实例,不同实例是可以并行执行;
相当于synchronized(Object obj),obj为非static;


匆忙写作,有不对的地方。可以评论留言,欢迎指正;

原创粉丝点击