1.Synchronized关键字的作用:能够保证在同一时刻最多只有一个线程执行该段代码,以达到保证并发安全的效果。
2.Synchronized的两个用法:
对象锁:包括方法锁(默认锁对象为this当前实例对象)和同步代码块锁(自己指定锁对象)
方法锁举例:
public class SynchronizedObjectMethod implements Runnable {
static SynchronizedObjectMethod instance = new SynchronizedObjectMethod();
@Override
public void run() {
method();
}
public synchronized void method() {
System.out.println("我是对象锁的方法修饰符形式,我叫" + Thread.currentThread().getName());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "运行结束");
}
public static void main(String[] args) {
Thread t1 = new Thread(instance);
Thread t2 = new Thread(instance);
t1.start();
t2.start();
while (t1.isAlive() || t2.isAlive()) {
}
System.out.println("finished");
}
}
同步代码块形式:
public class SynchronizedObjectCodeBlock implements Runnable {
static SynchronizedObjectCodeBlock instance = new SynchronizedObjectCodeBlock();
Object lock = new Object();
@Override
public void run() {
synchronized (lock) { //默认为this为当前的实例化对象
System.out.println("我是对象锁的代码块形式,我叫" + Thread.currentThread().getName());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "运行结束");
}
}
public static void main(String[] args) {
Thread t1 = new Thread(instance);
Thread t2 = new Thread(instance);
t1.start();
t2.start();
while (t1.isAlive() || t2.isAlive()) {
}
System.out.println("finished");
}
}
类锁:指synchronized修饰静态的方法或指定锁为Class对象
概念:java类可能有很多个对象,但只有1个Class对象,所谓的类锁,本质上是Class对象的锁。类锁只能在同一时刻被一个对象拥有。
形式1:synchronized加在static方法上
public class SynchronizedClassStatic implements Runnable {
static SynchronizedClassStatic instance1 = new SynchronizedClassStatic();
static SynchronizedClassStatic instance2 = new SynchronizedClassStatic();
@Override
public void run() {
method();
}
public static synchronized void method() {
System.out.println("我是类锁的第一种形式:static形式,我叫" + Thread.currentThread().getName());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "运行结束");
}
public static void main(String[] args) {
Thread t1 = new Thread(instance1);
Thread t2 = new Thread(instance2);
t1.start();
t2.start();
while (t1.isAlive() || t2.isAlive()) {
}
System.out.println("finished");
}
}
形式2:synchronized(*.class)代码块
public class SynchronizedClassClass implements Runnable {
static SynchronizedClassClass instance1 = new SynchronizedClassClass();
static SynchronizedClassClass instance2 = new SynchronizedClassClass();
@Override
public void run() {
method();
}
public void method() {
synchronized (SynchronizedClassClass.class) {
System.out.println("我是类锁的第二种形式:synchronized(*.class)形式,我叫" + Thread.currentThread().getName());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "运行结束");
}
}
public static void main(String[] args) {
Thread t1 = new Thread(instance1);
Thread t2 = new Thread(instance2);
t1.start();
t2.start();
while (t1.isAlive() || t2.isAlive()) {
}
System.out.println("finished");
}
}
3.多线程访问同步方法的7种情况:
(1)两个线程同时访问一个对象(实例)的同步方法:使用的是同一把锁,会产生同步效果。
(2)两个线程访问的是两个对象(实例)的同步方法:synchronized不起作用,因为采用的所对象不是同一个。
(3)两个线程访问的是synchronized的静态方法:锁生效,因为方法是静态的,所以它们对应的锁对象是同一把。
(4)同时访问同步方法和非同步方法:非同步方法不受到影响,同时运行。
(5)访问同一个对象的不同的普通同步方法:产生同步,锁对象都是this,同一把锁
(6)同时访问静态synchronized和非静态synchronized方法:同时运行,因为指定的锁对象不是同一把锁
(7)方法抛异常后,会释放锁
- 一把锁只能同时被一个线程获取,没有拿到锁的线程必须等待(对应情况1,5)
- 每个实例都对应有自己的一把锁,不同实例之间互不影响;例外:锁对象是*.class以及synchronized修饰的是static方法的时候,所有对象共用同一把锁(对应情况2,3,4,6)
- 无论是方法正常执行完毕或者方法抛出异常,都会释放锁(对应情况7)