Synchronized
Synchronized 作用:能够保证在同一时刻最多只有一个线程执行该段代码,以保证并发安全的效果。
对象锁:
包括方法锁(默认锁对象为this当前的实列对象)和同步代码块锁(自己指定锁对象)
代码块形式:手动指定锁对象
方法锁形式:synchronized 修饰普通的方法,锁对象默认为this
代码块形式:
/**
* 对象锁实列yi,代码块形式
*/
public class SychronizedObjectCodeBlock2 implements Runnable{
static SychronizedObjectCodeBlock2 installce = new SychronizedObjectCodeBlock2();
public static void main(String[] args) {
Thread t1 = new Thread(installce);
Thread t2 = new Thread(installce);
t1.start();
t2.start();
while (t1.isAlive() || t2.isAlive()){
}
System.out.println("Finshed");
}
Object lock = new Object();
Object lock2 = new Object();
@Override
public void run() {
synchronized (lock) {
System.out.println("我是对象锁的代码块形式llock,我叫" + Thread.currentThread().getName());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "运行完毕");
}
synchronized (lock2) {
System.out.println("我是对象锁的代码块形式lock2,我叫" + Thread.currentThread().getName());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "运行完毕");
}
}
}
方法锁:
/**
* 方法锁实例
*/
public class SychronizedObjectMethod2 implements Runnable{
static SychronizedObjectMethod2 installce = new SychronizedObjectMethod2();
public static void main(String[] args) {
Thread t1 = new Thread(installce);
Thread t2 = new Thread(installce);
t1.start();
t2.start();
while (t1.isAlive() || t2.isAlive()){
}
System.out.println("Finshed");
}
@Override
public void run() {
methods();
}
public synchronized void methods() {
System.out.println("我是对象锁的方法修饰形式,我叫"+Thread.currentThread().getName());
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"运行结束");
}
}
类锁:
指synchronized 修饰的静态方法或者指定锁为class 对象。
概念:JAVA可能有很多个对象,但只有1个class 对象
形式1 :synchronized 加在static 方法上
形式二:synchronized(*.class) 代码块
概念:只有一个class对象:java类可能又很多个对象,但只有一个class对象
本质:所以所谓的类锁,不过是class对象锁而已
用法和效果:类锁只能在同一时刻被一个对象所拥有
形式一:
/**
* 类锁的第一种形式 ,static 形式
*/
public class SychronizedClassStatic4 implements Runnable{
static SychronizedClassStatic4 instance1 =new SychronizedClassStatic4();
static SychronizedClassStatic4 instance2 =new SychronizedClassStatic4();
@Override
public void run() {
methods();
}
public static synchronized void methods() {
System.out.println("我是类锁的d第一种形式:static 。我叫" + 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 t1 = new Thread(instance1);
Thread t2 = new Thread(instance2);
t1.start();
t2.start();
while (t1.isAlive() || t2.isAlive()){
}
System.out.println("Finshed");
}
}
形式二:
/**
*
*/
public class SychronizedClassClass implements Runnable{
static SychronizedClassClass instance1 =new SychronizedClassClass();
static SychronizedClassClass instance2 =new SychronizedClassClass();
@Override
public void run() {
method();
}
public void method(){
synchronized (SychronizedClassClass.class){
System.out.println("我是类锁的第二种形式(*.class)。我叫"+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 t1 = new Thread(instance1);
Thread t2 = new Thread(instance2);
t1.start();
t2.start();
while (t1.isAlive() || t2.isAlive()){
}
System.out.println("Finshed");
}
}
面试易问问题:
- 两个线程同时访问一个对象的同步方法。
- 两个线程访问的是两个对象的同步方法。
- 两个线程访问的是synchronized的静态方法。
- 同时访问同步方法与非同步方法。(非同步方法不受影响)
- 访问同一个对象的不同的普通同步方法。
- 同时访问静态synchronize的非静态的synchronized方法。
- 方法抛出异常,会释放锁’
核心思想:
- 一把锁只能同时被一个线程获取,没有拿到锁的线程必须等待(对应上面的1,5);
- 每个实列都对应有自己的一把锁不同实列互不影响;列外:锁对象是 *.class以及sychronizde修饰的是static 方法的时候,所有对象·共用同意把锁(对应2,3,4,6中情况);
- 无论是方法正常执行完毕还是方法抛出异常,都是释放锁(对应第7中情况)
4.补充:synchronized方法里用了没被synchronized修饰的方法,是不线程安全的
性质:
- 可重入,2 不可中断 ,
可重入:可重入是指同一个线程的外层函数获得锁之后,内层函数可以直接再次获取该锁;
不可重入:一个线程拿到锁了,如果需要再次使用该锁,必须先释放该锁才能再次获取
synchronized是可重入锁
可重入锁的好处:
1 避免死锁 2 提升封装性
粒度:可重入的特性是线程级别的,不是调用级别的