作用:能够保证在同一时刻最多只有一个线程执行该段代码,以达到保证并发安全的效果。
地位:java关键字,是最基本的互斥同步手段,并发编程中必学
不使用并发:例如,我们做一个简单的累加,累加10万次,利用两个线程,那么应该一共是累加到20万,
但是实际结果我们会发现,根本不会到20万,基本到是14万这种的,这就是没有使用Synchronized导致的后果。在每次累加的时候,一次累加包含读取值,加一,写入内存三个操作。例如,线程a在执行加一的时候,在读取值5,然后加一了变成6,在没有写入写存的时候,线程b就执行了读取值,这个时候读取的也是5,然后加一变成6写入内存,这也就是为什么两个线程在累加的时候,最终的结果会小于20万的原因了。这种情况,也就是我们通常所说的线程不安全,因为没有加锁。
方法锁:默认锁对象为this当前实例对象。
同步代码块锁:自己制定锁对象。
类锁:Synchronized修饰的静态方法或制指定锁为class对象。
在类中加入Synchronized,可以保证程序是串行执行的,如果没有加,那么代码块就会是并行执行,也就是会同时执行的。Synchronized(this){};最关键的就是锁的对象的选取,这里选取的是this,当前对象。对于需要锁住的对象,要根据具体的业务逻辑来选取。
多线程访问同步的七种情况:
1:两个线程同时访问一个对象的同步方法(串行,同一个实例,同一把锁,需要等待)
2:两个线程同时访问两个对象的同步方法(并行,锁的是不同对象)
3:两个线程访问的是Synchronized的静态方法(串行,只要是静态的,锁的对象就是同一把)
4:同时访问同步方法和非同步方法(同时执行,同时结束,并行)
5:访问同一个对象的不相同的普通同步方法(非静态)(一个先执行结束,后一个再执行结束,串行)
6:同时访问静态Synchronized方法和非静态Synchronized方法(同时开始,同时结束。锁指定的所对象不是同一个锁)
7:方法抛异常后,会释放锁(第一个线程异常,但是第二个线程可以运行,则说明锁释放了)
总结:
1.一把锁只能同时被一个线程获取,没有拿到锁的线程必须等待
2.每个实例都对应自己的一把锁,不同实例之间互不影响,锁对象是*.class以及synchronized修饰的static方法的时候,所有对象共用同一把类锁
3.无论是方法正常执行或者方法抛出异常,都会释放锁