synchronized 总结

方法锁形式: synchronized 修饰普通方法, 锁对象默认为 this ,也就是当前实例对象html

 

注意若是是 不一样 类锁的 不一样 的同步代码块。状况是有点特殊的,虽然也是有顺序了。java

package com.my.com.my.sysnc;

/**
 * 同步锁测试
 */
public class TestSynchronized implements  Runnable{

    static  TestSynchronized instance=new TestSynchronized();

    Object lock1=new Object();
    Object lock2=new Object();

    @Override
    public void run() {



        synchronized (lock1){
            System.out.println("lock1对象锁代码块,线程名"+Thread.currentThread().getName());

            try {
                Thread.sleep(300);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println(Thread.currentThread().getName()+"结束lock1");
        }

        synchronized (lock2){
            System.out.println("lock2对象锁代码块,线程名"+Thread.currentThread().getName());

            try {
                Thread.sleep(300);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println(Thread.currentThread().getName()+"结束lock2");
        }



    }

   


    public static void main(String[] args) {

        Thread thread1=new Thread(instance);
        Thread thread2=new Thread(instance);
        thread1.start();
        thread2.start();

    }

}



结果  即 ,在run 方法里面, 当 第一个线程执行完 第一个同步代码块的时候,在开始执行第一个代码块的时候。
此时 第二个线程会去执行第一个同步代码块。 这样就有 点并行执行了
:

lock1对象锁代码块,线程名Thread-0
Thread-0结束lock1
lock2对象锁代码块,线程名Thread-0
lock1对象锁代码块,线程名Thread-1
Thread-0结束lock2
Thread-1结束lock1
lock2对象锁代码块,线程名Thread-1
Thread-1结束lock2

 

 

 

 

类锁面试

 

 

 

若是是对象锁的话,那么不一样的对象对于不一样的线程来讲,就不会起到 锁的做用了。ide

若是是 类锁的话,那么就能够作到 不一样的对象对于不一样的线程 起到 锁的做用。函数

普通方法: 即非 静态方法测试

 

抛出异常的适合, LOCK 锁不会释放锁,而 synchronized  会释放锁this

 

面试题spa

1. 两个线程同时访问一个对象的同步方法:.net

可以锁住,同一个实例线程

2. 两个线程访问的是两个对象的同步方法。

由于不一样的实例全部并无锁的做用,锁对象不是同一个

3. 两个线程访问的是 synchronized 的静态方法

锁的是 class对象, 锁住 

4. 同时访问同步方法与非同步方法

同步方法不能影响 非同步方法。 

同步方法与非同步方法能够同时运行

 

5. 访问同一个对象的不一样的普通同步方法

方法不能同时的运行。 锁的是同一个对象。受锁的影响

例子:

package com.my.com.my.sysnc;

/**
 * 同步锁测试
 */
public class TestSynchronized implements  Runnable{

    static  TestSynchronized instance=new TestSynchronized();

    @Override
    public void run() {

       if (Thread.currentThread().getName().equals("Thread-0")){
           test1();
       }else{
           test2();
       }


    }

    public  synchronized void test1(){
        System.out.println("对象锁代码块"+Thread.currentThread().getName());

        try {
            Thread.sleep(300);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println(Thread.currentThread().getName()+"结束线程");
    }

    public  synchronized void test2(){
        System.out.println("对象锁代码块"+Thread.currentThread().getName());

        try {
            Thread.sleep(300);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println(Thread.currentThread().getName()+"结束线程");
    }


    public static void main(String[] args) {

        Thread thread1=new Thread(instance);
        Thread thread2=new Thread(instance);
        thread1.start();
        thread2.start();

    }

}

 锁的是同一个实例,竞争的是同一个实例,因此受到影响

可能的结果 :
对象锁代码块Thread-1
Thread-1结束线程
对象锁代码块Thread-0
Thread-0结束线程

 

6. 同时访问静态 synchronized 和 非静态 synchronized 方法

锁不其做用,两个方法均可以一块儿运行。

由于静态锁的是 class 对象,非静态的 锁的是 实例对象。是不同的

package com.my.com.my.sysnc;

/**
 * 同步锁测试
 */
public class TestSynchronized implements  Runnable{

    static  TestSynchronized instance=new TestSynchronized();

    Object lock1=new Object();
    Object lock2=new Object();

    @Override
    public void run() {

       if (Thread.currentThread().getName().equals("Thread-0")){
           test1();
       }else{
           test2();
       }




    }

    public static   synchronized void test1(){
        System.out.println("静态加锁方法1,,对象锁代码块"+Thread.currentThread().getName());

        try {
            Thread.sleep(300);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println(Thread.currentThread().getName()+"结束线程");
    }

    public  synchronized void test2(){
        System.out.println("非静态加锁方法2,对象锁代码块"+Thread.currentThread().getName());

        try {
            Thread.sleep(300);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println(Thread.currentThread().getName()+"结束线程");
    }


    public static void main(String[] args) {

        Thread thread1=new Thread(instance);
        Thread thread2=new Thread(instance);
        thread1.start();
        thread2.start();

    }

}

结果:
非静态加锁方法2,对象锁代码块Thread-1
静态加锁方法1,,对象锁代码块Thread-0
Thread-0结束线程
Thread-1结束线程

 

 

7. 方法抛异常后,会释放锁

 

package com.my.com.my.sysnc;

/**
 * 同步锁测试
 */
public class TestSynchronized implements  Runnable{

    static  TestSynchronized instance=new TestSynchronized();

    Object lock1=new Object();
    Object lock2=new Object();

    @Override
    public void run() {

       if (Thread.currentThread().getName().equals("Thread-0")){
           test1();
       }else{
           test2();
       }




    }

    public    synchronized void test1(){
        System.out.println("对象锁代码块"+Thread.currentThread().getName());

        try {
            Thread.sleep(300);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    // 抛出异常后,释放锁,由JVM处理释放锁
       throw  new RuntimeException("抛出异常");
    }

    public  synchronized void test2(){
        System.out.println("对象锁代码块"+Thread.currentThread().getName());

        try {
            Thread.sleep(300);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println(Thread.currentThread().getName()+"结束线程");
    }


    public static void main(String[] args) {

        Thread thread1=new Thread(instance);
        Thread thread2=new Thread(instance);
        thread1.start();
        thread2.start();

    }

}


结果:
对象锁代码块Thread-0
对象锁代码块Thread-1
Exception in thread "Thread-0" java.lang.RuntimeException: 抛出异常
	at com.my.com.my.sysnc.TestSynchronized.test1(TestSynchronized.java:36)
	at com.my.com.my.sysnc.TestSynchronized.run(TestSynchronized.java:17)
	at java.lang.Thread.run(Thread.java:748)
Thread-1结束线程

 



性质

1, 可重入:避免死锁,提高封装性

指的是 同一线程的外层函数得到锁以后,内层函数能够之间再次获取该锁

 

同一个方法可重入(好比递归调用),

不要求同一个方法也能够重入(好比同一个类中调用2个都是锁的方法) ,

可重入不要求 是同一个类中的(子类的 重写父类的加锁方法,并调用父类的加锁方法)

 

2,不可中断 

 

 

 

 

 

 

3. 粒度

 

线程而非调用

 

 

原理

由于每个对象均可以做为 锁的部分。

因此每一个对象都有一个 内置锁。 

线程在进入 synchronized 里面以前,会获取 synchronized 锁的对象的 内置锁。

当 执行完 synchronized 的 锁的代码后,会释放 对应的对象的 内置锁。

Java 对象的对象头有一个 字段用来讲明是否锁住了,因此 synchronized  做用就是 根据这个字段来 锁的

编译执行的时候 ,JVM 经过   Java的 指令  monitorenter 进入 锁(monitor计数器加1),  monitorexit 退出 锁(monitor计数器减1)。

经过判断  monitor 数字 判断是否 是否能够获取锁 。

注意虽然synchronized 锁 等价于  Lock 锁。 可是他们其实仍是有所区别的。

lock 锁并非锁当前的 this 对象的。

package com.my.com.my.sysnc;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 同步锁测试
 */
public class TestSynchronized implements  Runnable{

    static  TestSynchronized instance=new TestSynchronized();

    Lock lock=new ReentrantLock();



    @Override
    public void run() {


      test1();
        test2();




    }

    public    synchronized void test1(){
        System.out.println("synchronized对象锁代码块"+Thread.currentThread().getName());

        try {
            Thread.sleep(300);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("synchronized对象锁代码块结束"+Thread.currentThread().getName());
    }

    public   void test2(){

        lock.lock();
        try {
            System.out.println("lock对象锁代码块"+Thread.currentThread().getName());

            try {
                Thread.sleep(300);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }finally {
            //不释放锁
          //  lock.unlock();
        }



        System.out.println(Thread.currentThread().getName()+"结束线程lock");
    }


    public static void main(String[] args) {

        Thread thread1=new Thread(instance);
        Thread thread2=new Thread(instance);
        thread1.start();
        thread2.start();

    }

}


线程0 在lock 执行后,并无释放lock 锁。
因此线程1 会在 lock 处等待。 由于 lock 不是 锁当前this 对象, 因此 线程1 能够执行 synchronized 锁方法
结果:


synchronized对象锁代码块Thread-0
synchronized对象锁代码块结束Thread-0
lock对象锁代码块Thread-0
synchronized对象锁代码块Thread-1
Thread-0结束线程lock
synchronized对象锁代码块结束Thread-1

 

 

 

 

 

 

 

注意点

1, 锁对象不能为空,做用域不宜过大,避免死锁

2, 如何选择 Lock 和 synchronized 关键字

21, 能使用 synchronized 优先使用,可以使代码更简化

22.   要使用 LOCK 的独有特性才考虑 lock  

23. 总之就是 避免出错,追求稳定的

 

synchronized非公平锁,ReentrantLock能够设置是否公平锁

参考 https://www.cnblogs.com/twoheads/p/10150063.html

优势 缺点 适用场景
偏向锁 加锁和解锁不须要额外的消耗,与执行非同步方法仅存在纳秒级的差距 若是线程间存在竞争,会带来额外的锁撤销的消耗 适用于只有一个线程访问同步块的状况
轻量级锁 竞争的线程不会堵塞,提升了程序的响应速度 始终得不到锁的线程,使用自旋会消耗CPU 追求响应时间,同步块执行速度很是块,只有两个线程竞争锁
重量级锁 线程竞争不使用自旋,不会消耗CPU 线程堵塞,响应时间缓慢 追求吞吐量,同步块执行速度比较慢,竞争锁的线程大于2个

 

 

以上来自慕课网

相关文章
相关标签/搜索