澳门新葡萄京官网首页 10

澳门新葡萄京官网首页Java并发编程:深入了解synchronized关键字

synchronized 关键字解析

同步锁依赖于对象,每个对象都有一个同步锁。

现有一成员变量 Test,当线程 A 调用 Test 的 synchronized 方法,线程 A
获得 Test 的同步锁,同时,线程 B 也去调用 Test 的 synchronized
方法,此时线程 B 无法获得 Test 的同步锁,必须等待线程 A 释放 Test
的同步锁才能获得从而执行对应方法的代码。

综上,正确使用 synchronized 关键字可确保原子性。

目录

前言

本篇主要介绍Java多线程中的同步,也就是如何在Java语言中写出线程安全的程序,如何在Java语言中解决非线程安全的相关问题。没错就是使用synchronized。

synchronized 关键字的特性应用

1:synchronized简介

正文

特性 1:

当线程 A
调用某对象synchronized 方法 或者 synchronized 代码块时,若同步锁未释放,其他线程调用同一对象synchronized 方法 或者 synchronized 代码块时将被阻塞,直至线程
A 释放该对象的同步锁。

DEMO1,synchronized 方法:

public class Test {

    private static class Counter {

        public synchronized void count() {
            for (int i = 0; i < 6; i++) {
                System.out.println(Thread.currentThread().getName() + ", i = " + i);
            }
        }

    }

    private static class MyThread extends Thread {

        private Counter mCounter;

        public MyThread(Counter counter) {
            mCounter = counter;
        }

        @Override
        public void run() {
            super.run();
            mCounter.count();
        }
    }

    public static void main(String[] var0) {
        Counter counter = new Counter();
        // 注:myThread1 和 myThread2 是调用同一个对象 counter
        MyThread myThread1 = new MyThread(counter);
        MyThread myThread2 = new MyThread(counter);
        myThread1.start();
        myThread2.start();
    }

}

DEMO1 输出:

Thread-0, i = 0
Thread-0, i = 1
Thread-0, i = 2
Thread-0, i = 3
Thread-0, i = 4
Thread-0, i = 5
Thread-1, i = 0
Thread-1, i = 1
Thread-1, i = 2
Thread-1, i = 3
Thread-1, i = 4
Thread-1, i = 5

DEMO2,synchronized 代码块:

public class Test {

    private static class Counter {

        public void count() {
            synchronized (this) {
                for (int i = 0; i < 6; i++) {
                    System.out.println(Thread.currentThread().getName() + ", i = " + i);
                }
            }
        }
    }

    private static class MyThread extends Thread {

        private Counter mCounter;

        public MyThread(Counter counter) {
            mCounter = counter;
        }

        @Override
        public void run() {
            super.run();
            mCounter.count();
        }
    }

    public static void main(String[] var0) {
        Counter counter = new Counter();
        MyThread myThread1 = new MyThread(counter);
        MyThread myThread2 = new MyThread(counter);
        myThread1.start();
        myThread2.start();
    }
}

DEMO2 输出:

Thread-0, i = 0
Thread-0, i = 1
Thread-0, i = 2
Thread-0, i = 3
Thread-0, i = 4
Thread-0, i = 5
Thread-1, i = 0
Thread-1, i = 1
Thread-1, i = 2
Thread-1, i = 3
Thread-1, i = 4
Thread-1, i = 5

可见,当同步锁未释放时,其他线程将被阻塞,直至获得同步锁。

而且 DEMO1 和 DEMO2
的输出结果是一样的,synchronized 方法 和 synchronized 代码块的不同之处在于 synchronized 方法 作用域较大,作用于整个方法,而 synchronized 代码块 可控制具体的作用域,更精准控制提高效率。(毕竟阻塞的都是时间啊)

DEMO3,仅修改 main 方法:

    public static void main(String[] var0) {
        // 注意:myThread1 和 myThread2 传入的 Counter 是两个不同的对象
        MyThread myThread1 = new MyThread(new Counter());
        MyThread myThread2 = new MyThread(new Counter());
        myThread1.start();
        myThread2.start();
    }

DEMO3 输出:

Thread-0, i = 0
Thread-1, i = 0
Thread-0, i = 1
Thread-1, i = 1
Thread-1, i = 2
Thread-1, i = 3
Thread-0, i = 2
Thread-1, i = 4
Thread-0, i = 3
Thread-1, i = 5
Thread-0, i = 4
Thread-0, i = 5

同步锁基于对象,只要锁的来源一致,即可达到同步的作用。所以,但对象不一样,则不能达到同步效果。

2:synchronized使用方式

如何解决线程安全问题?

那么一般来说,是如何解决线程安全问题的呢?

基本上所有的并发模式在解决线程安全问题时,都采用“序列化访问临界资源”的方案,即在同一时刻,只能有一个线程访问临界资源,也称作同步互斥访问。

通常来说,是在访问临界资源的代码前面加上一个锁,当访问完临界资源后释放锁,让其他线程继续访问。

在Java中,提供了两种方式来实现同步互斥访问:synchronized和Lock。

本文主要讲述synchronized的使用方法,Lock的使用方法在下一篇博文中讲述。

特性 2:

当线程 A
调用某对象synchronized 方法 或者 synchronized 代码块时,若同步锁未释放,其他线程调用同一对象其他``synchronized 方法 或者 synchronized 代码块时将被阻塞,直至线程
A 释放该对象的同步锁。(注意:重点是其他

DEMO4,仅修改 doOtherThings 方法的修饰:

public class Test {

    private static class Counter {

        public synchronized void count() {
            System.out.println(Thread.currentThread().getName() + " sleep");
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + " awake");
        }

        public synchronized void doOtherThings(){
            System.out.println(Thread.currentThread().getName() + " doOtherThings");
        }
    }

    public static void main(String[] var0) {
        final Counter counter = new Counter();
        new Thread(new Runnable() {
            @Override
            public void run() {
                counter.count();
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                counter.doOtherThings();
            }
        }).start();
    }
}

DEMO4 输出:

Thread-0 sleep
Thread-0 awake
Thread-1 doOtherThings

可见,synchronized 获得的同步锁并非仅仅锁住代码,而是锁住整个对象。

此时应提及 happens-before 原则,正因 happens-before
原则的存在才有此现象的发生。
happens-before 原则的其中一条:

管理锁定原则:一个 unLock 操作先行发生于后面对同一个锁的 lock
操作。

(此处暂不作过多解释,解释起来能再写一篇文章了)

DEMO5,仅修改 doOtherThings 方法:

        public void doOtherThings(){
            synchronized (this){
                System.out.println(Thread.currentThread().getName() + " doOtherThings");
            }
        }

澳门新葡萄京官网首页,DEMO5 输出:

Thread-0 sleep
Thread-0 awake
Thread-1 doOtherThings

DEMO4 和 DEMO5
的输出结果竟然一致!没错,因为他们的同步锁来源一致(都是本实例自己),所以可以达到同步效果。

// 这两个 synchronized 锁的是同一个对象
public synchronized void count(){};
public void doOtherThings(){
       synchronized (this){}
}

DEMO6,去掉 doOtherThings 方法的同步关键字:

public void doOtherThings(){
            System.out.println(Thread.currentThread().getName() + " doOtherThings");
        }

DEMO6 输出:

Thread-0 sleep
Thread-1 doOtherThings
Thread-0 awake

当线程 A
调用某对象synchronized 方法 或者 synchronized 代码块时,无论同步锁是否释放,其他线程调用同一对象其他 非 synchronized 方法 或者 非 synchronized 代码块时可立即调用。

3:synchronized可重入性

synchronized同步方法

synchronized是Java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码。在了解synchronized关键字的使用方法之前,我们先来看一个概念:互斥锁,顾名思义:能到达到互斥访问目的的锁。

举个简单的例子:如果对临界资源加上互斥锁,当一个线程在访问该临界资源时,其他线程便只能等待。

在Java中,每一个对象都拥有一个锁标记(monitor),也称为监视器,多线程同时访问某个对象时,线程只有获取了该对象的锁才能访问。

在Java中,可以使用synchronized关键字来标记一个方法或者代码块,当某个线程调用该对象的synchronized方法或者访问synchronized代码块时,这个线程便获得了该对象的锁,其他线程暂时无法访问这个方法,只有等待这个方法执行完毕或者代码块执行完毕,这个线程才会释放该对象的锁,其他线程才能执行这个方法或者代码块。

实例锁和全局锁

以上 DEMO 实现的都是实例锁。锁住(作用域)的是具体某一对象实例。

什么是全局锁?

锁住整个 Class,而非某个对象或实例。

注:单例型的实例锁不属于全局锁。

4:synchronized可见性

synchronized的使用

  • synchronized代码块,被修饰的代码成为同步语句块,其作用的范围是调用这个代码块的对象,我们在用synchronized关键字的时候,能缩小代码段的范围就尽量缩小,能在代码段上加同步就不要再整个方法上加同步。这叫减小锁的粒度,使代码更大程度的并发。

  • synchronized方法,被修饰的方法成为同步方法,其作用范围是整个方法,作用对象是调用这个方法的对象。

  • synchronized静态方法,修饰一个static静态方法,其作用范围是整个静态方法,作用对象是这个类的所有对象。

  • synchronized类,其作用范围是Synchronized后面括号括起来的部分synchronized(className.class),作用的对象是这个类的所有对象。

  • synchronized(),()中是锁住的对象,
    synchronized(this)锁住的只是对象本身,同一个类的不同对象调用的synchronized方法并不会被锁住,而synchronized(className.class)实现了全局锁的功能,所有这个类的对象调用这个方法都受到锁的影响,此外()中还可以添加一个具体的对象,实现给具体对象加锁。

synchronized (object) {
  //在同步代码块中对对象进行操作
}

全局锁的实现:

静态 synchronized 方法

DEMO7:

public class Test {

    private static class Counter {

        public static synchronized void count() {
            System.out.println(Thread.currentThread().getName() + " sleep");
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + " awake");
        }

        public static synchronized void doOtherThings(){
            System.out.println(Thread.currentThread().getName() + " doOtherThings");
        }
    }

    public static void main(String[] var0) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                Counter.count();
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                Counter.doOtherThings();
            }
        }).start();
    }
}

DEMO7 输出:

Thread-0 sleep
Thread-0 awake
Thread-1 doOtherThings

static 声明的方法为全局方法,与对象实例化无关,所以 static synchronized
方法为全局同步方法,与对象实例化无关。

5:synchronized实现原理

synchronized注意事项

  • 当两个并发线程访问同一个对象中的synchronized代码块时,在同一时刻只能有一个线程得到执行,另一个线程受阻塞,必须等待当前线程执行完这个代码块以后才能执行该代码块。两个线程间是互斥的,因为在执行synchronized代码块时会锁定当前的对象,只有执行完该代码块才能释放该对象锁,下一个线程才能执行并锁定该对象。

  • 当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。(两个线程使用的是同一个对象)

  • 当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞(同上,两个线程使用的是同一个对象)。

下面通过代码来实现:

1)当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。

package ths;

public class Thread1 implements Runnable {  
     public void run() {  
          synchronized(this) {  
               for (int i = 0; i < 5; i++) {  
                    System.out.println(Thread.currentThread().getName() + " synchronized loop " + i);  
               }  
          }  
     }  
     public static void main(String[] args) {  
          Thread1 t1 = new Thread1();  
          Thread ta = new Thread(t1, "A");  
          Thread tb = new Thread(t1, "B");  
          ta.start();  
          tb.start();  
     } 
}

输出结果:

A synchronized loop 0  
A synchronized loop 1  
A synchronized loop 2  
A synchronized loop 3  
A synchronized loop 4  
B synchronized loop 0  
B synchronized loop 1  
B synchronized loop 2  
B synchronized loop 3  
B synchronized loop 4

2)然而,当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。

package ths;

public class Thread2 {  
     public void m4t1() {  
          synchronized(this) {  
               int i = 5;  
               while( i-- > 0) {  
                    System.out.println(Thread.currentThread().getName() + " : " + i);  
                    try {  
                         Thread.sleep(500);  
                    } catch (InterruptedException ie) {  
                    }  
               }  
          }  
     }  
     public void m4t2() {  
          int i = 5;  
          while( i-- > 0) {  
               System.out.println(Thread.currentThread().getName() + " : " + i);  
               try {  
                    Thread.sleep(500);  
               } catch (InterruptedException ie) {  
               }  
          }  
     }  
     public static void main(String[] args) {  
          final Thread2 myt2 = new Thread2();  
          Thread t1 = new Thread(  new Runnable() {  public void run() {  myt2.m4t1();  }  }, "t1"  );  
          Thread t2 = new Thread(  new Runnable() {  public void run() { myt2.m4t2();   }  }, "t2"  );  
          t1.start();  
          t2.start();  
     } 
}

输出结果:

t1 : 4  
t2 : 4  
t1 : 3  
t2 : 3  
t1 : 2  
t2 : 2  
t1 : 1  
t2 : 1  
t1 : 0  
t2 : 0

3)尤其关键的是,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。

//修改Thread2.m4t2()方法:  
     public void m4t2() {  
          synchronized(this) {  
               int i = 5;  
               while( i-- > 0) {  
                    System.out.println(Thread.currentThread().getName() + " : " + i);  
                    try {  
                         Thread.sleep(500);  
                    } catch (InterruptedException ie) {  
                    }  
               }  
          }

     }

输出结果:

t1 : 4  
t1 : 3  
t1 : 2  
t1 : 1  
t1 : 0  
t2 : 4  
t2 : 3  
t2 : 2  
t2 : 1  
t2 : 0

4)第三个例子同样适用其它同步代码块。也就是说,当一个线程访问object的一个synchronized(this)同步代码块时,它就获得了这个object的对象锁。结果,其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。

 //修改Thread2.m4t2()方法如下:

     public synchronized void m4t2() {  
          int i = 5;  
          while( i-- > 0) {  
               System.out.println(Thread.currentThread().getName() + " : " + i);  
               try {  
                    Thread.sleep(500);  
               } catch (InterruptedException ie) {  
               }  
          }  
     }

输出结果:

t1 : 4  
t1 : 3  
t1 : 2  
t1 : 1  
t1 : 0  
t2 : 4  
t2 : 3  
t2 : 2  
t2 : 1  
t2 : 0

5)每个类也会有一个锁,它可以用来控制对static数据成员的并发访问。
并且如果一个线程执行一个对象的非static
synchronized方法,另外一个线程需要执行这个对象所属类的static
synchronized方法,此时不会发生互斥现象,因为访问static
synchronized方法占用的是类锁,而访问非static
synchronized方法占用的是对象锁,所以不存在互斥现象。
代码如下:

public class Test {

    public static void main(String[] args)  {
        final InsertData insertData = new InsertData();
        new Thread(){
            @Override
            public void run() {
                insertData.insert();
            }
        }.start(); 
        new Thread(){
            @Override
            public void run() {
                insertData.insert1();
            }
        }.start();
    }  
}

class InsertData { 
    public synchronized void insert(){
        System.out.println("执行insert");
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("执行insert完毕");
    }

    public synchronized static void insert1() {
        System.out.println("执行insert1");
        System.out.println("执行insert1完毕");
    }
}

输出结果:

执行insert
执行insert1
执行insert1完毕
执行insert完毕

第一个线程里面执行的是insert方法,不会导致第二个线程执行insert1方法发生阻塞现象。

synchronized 具体 Class 的代码块

DEMO8:

public class Test {

    private static class Counter {

        public static synchronized void count() {
            System.out.println(Thread.currentThread().getName() + " sleep");
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + " awake");
        }

        public void doOtherThings(){
            synchronized (Counter.class){
                System.out.println(Thread.currentThread().getName() + " doOtherThings");
            }
        }
    }

    public static void main(String[] var0) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                Counter.count();
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                Counter counter = new Counter();
                counter.doOtherThings();
            }
        }).start();
    }
}

DEMO8 输出:

Thread-0 sleep
Thread-0 awake
Thread-1 doOtherThings

synchronized (Counter.class) 获得的同步锁是全局的,static synchronized
获得的同步锁也是全局的,同一个锁,所以达到同步效果。

6:synchronized的缺陷

面试题

当一个线程进入一个对象的synchronized方法A之后,其它线程是否可进入此对象的synchronized方法B?
答:不能。其它线程只能访问该对象的非同步方法,同步方法则不能进入。因为非静态方法上的synchronized修饰符要求执行方法时要获得对象的锁,如果已经进入A方法说明对象锁已经被取走,那么试图进入B方法的线程就只能在等锁池(注意不是等待池哦)中等待对象的锁。

synchronized关键字的用法?
答:synchronized关键字可以将对象或者方法标记为同步,以实现对对象和方法的互斥访问,可以用synchronized(对象)
{ … }定义同步代码块,或者在声明方法时将synchronized作为方法的修饰符。

简述synchronized 和java.util.concurrent.locks.Lock的异同?
答:Lock是Java
5以后引入的新的API,和关键字synchronized相比主要相同点:Lock
能完成synchronized所实现的所有功能;主要不同点:Lock有比synchronized更精确的线程语义和更好的性能,而且不强制性的要求一定要获得锁。synchronized会自动释放锁,而Lock一定要求程序员手工释放,并且最好在finally
块中释放(这是释放外部资源的最好的地方)

区分 synchronized (this) 与 synchronized (Class.class)

DEMO9:

public class Test {

    private static class Counter {

        public void count() {
            synchronized (this){
                System.out.println(Thread.currentThread().getName() + " sleep");
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + " awake");
            }
        }

        public void doOtherThings(){
            synchronized (Counter.class){
                System.out.println(Thread.currentThread().getName() + " doOtherThings");
            }
        }
    }

    public static void main(String[] var0) {
        final Counter counter = new Counter();
        new Thread(new Runnable() {
            @Override
            public void run() {
                counter.count();
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                counter.doOtherThings();
            }
        }).start();
    }
}

DEMO9 输出:

Thread-0 sleep
Thread-1 doOtherThings
Thread-0 awake

synchronized (this) 获得的是具体对象实例 counter 的锁,而 synchronized
(Counter.class) 获得的是全局锁,两把不同的锁,所以不能达到同步效果。

7:synchronized的使用注意

总结

以上就是synchronized的概念和基本使用用法,下一篇博文中将介绍Lock,希望对你有所帮助。


一直觉得自己写的不是技术,而是情怀,一篇篇文章是自己这一路走来的痕迹。靠专业技能的成功是最具可复制性的,希望我的这条路能让你少走弯路,希望我能帮你抹去知识的蒙尘,希望我能帮你理清知识的脉络,希望未来技术之巅上有你也有我。

澳门新葡萄京官网首页 1

1:synchronized简介

在多线程环境中对同一资源同时操作可能会导致结果的不确定性。java内置了synchronized关键字来解决这种问题。synchronized通常也被称为重量级锁,尽管从JDK1.5新增了Lock,但synchronized凭借java自带的高封装性依旧被广泛的使用。synchronized可以把任何一个非null的对象作为锁。synchronized有两种主要用法:第一种是对象锁,包括方法锁(默认锁对象为this当前的实例对象)和同步代码块锁。第二种是类锁,指synchronized修饰静态的方法或指定锁为Class对象。2:synchronized使用方式

首先,我先写一段代码

澳门新葡萄京官网首页 2

这段代码大家应该可以看出来是有问题的,没有保证对共享变量i的原子操作,导致的结果就是:无法确定i输出的值。

下面来演示synchronized的几种用法,如何保证数据的准确性。

方式一: 同步代码块

澳门新葡萄京官网首页 3

this指的是当前的实例对象。

方式二: 同步方法

澳门新葡萄京官网首页 4

第二种方式也能够保证数据的准确。

下面我再对上述代码进行改动。实例化两个对象,分别给线程使用。这时会发现,上述的两种方式都尽管都使用了synchronized,但依然无法保证数据的准确。原因是因为我们使用的是synchronized的对象锁,对于不同的实例对象,线程只能够对自己引用的对象进行加锁。

澳门新葡萄京官网首页 5

演示下面用法的时候先讲一个概念:Java类可能有很多个对象,但只有1个Class对象。这个很重要,要考的!!!比如我new一个Student对象A,一个Student对象B,这是两个对象,但它们只有一个Class对象,这个Class对象由JVM实现。

方式三: 静态方法锁

与第二种方式相比就是在同步方法上多加了static

澳门新葡萄京官网首页 6

当作用在静态方法时锁住的便是对象对应的Class实例,因为Class数据存在于永久带,因此静态方法锁相当于该类的一个全局锁。所以就算new了多个对象,但一样能够锁住。

方式四: synchronized锁为Class对象

澳门新葡萄京官网首页 7

在方法四中,我们的锁对象是*.class,无论实例化多少对象,这些对象也只有一个class对象,所以,这种方式也是可以锁住的。3:synchronized可重入性

synchronized和Lock(ReentrantLock)都是可重入锁,可重入锁又叫做递归锁。在这里只说明synchronized的可重入性,不对二者进行比较。

可重入性定义:同一线程在外层函数获取到锁后,内层函数可以直接再次获取到锁。

synchronized的可重入性有两点好处:避免死锁,提升封装性。

这是什么意思呢?我们用如下代码来说明:

澳门新葡萄京官网首页 8

我们假设synchronized不具有重入性,在调用method2时,由于当前持有的锁没有释放,又无法获取到method2中的锁,这时就会导致死锁。

由于synchronized是java内置的锁,自带重入性,所以封装性更强。

原理:加锁次数计数器。

每个对象都有一把锁,JVM负责跟踪对象被加锁的次数。线程第一次获取对象锁的时候,计数变为1.当这个线程在此对象上再次获得锁的时候,计数会递增。当任务离开的时候,计数递减,当计数递减为0的时候,锁完全被释放。4:synchronized可见性

既然说到线程之间的可见性,那么必须要先了解java的内存模型JMM(这篇博客中简单简单讲解了一下java的内存模型:

澳门新葡萄京官网首页 9

5:synchronized实现原理

synchronized是java内置的关键字,由此可见它的重要性。但它无法直接通过源码来分析。下面我用反编译字节码信息来分析一下synchronized的实现原理。

先用javac将方法一中的.java文件编译成.class文件,执行javap -v
SynchronizedMethod1.class,javap是jdk自带的工具,想要仔细了解可以参考(

澳门新葡萄京官网首页 10

执行同步代码块需要先获取对象的监视器monitor。monitorenter对应多个monitorexit,释放锁的情况可能有多种,正常释放锁,异常释放锁,所以monitorexit相比较于monitorenter会多。6:synchronized的缺陷

锁的释放情况少。synchronized释放锁只有两种情况,一种是正常流程运行结束,另一种是发生了异常。如果说一个线程正在执行IO操作(当然,不建议在锁中进行耗时的IO操作,只是举例),那么另一个线程就只能焦急的等待。

试图获得锁时不能设置超时时间。排队获取锁的线程会一直存在,不会因为暂时的堵塞而撤退。与之对应的tryLock(long
time, TimeUnit unit) 在指定的时间内不能获得锁就会主动放弃。

不能中断一个正在试图获得锁的线程。

不够灵活:每个锁仅有单一的条件,加锁和释放锁的时机单一。

无法知道是否成功获取到锁。7:synchronized的使用注意

锁的对象不能为空,锁是存在于对象头中的,对象都没有,如何加锁。

锁的作用域不宜过大,简单点说就是加锁的代码块不能过多,如果代码块都存在与锁中,代
码的执行就变成了串行执行。这就无法体现多线程的效率了。

避免死锁。在一个线程中避免获取不同的锁。

记录自己的学习和成长,如果写的有什么不对的地方,还请大家多多指正。

发表评论

电子邮件地址不会被公开。 必填项已用*标注