先说结论,锁无非是锁两种:
- 非静态方法锁的当前实例对象this
- 静态方法锁的是当前类的class对象
- 代码块锁的是指定的对象
1、synchronzed修饰普通方法
package juctest;
import java.util.concurrent.TimeUnit;
public class LockTest1 {
/**
* 两个线程访问同一个synchronzied修饰的方法,资源类
* 其中谁先抢占着锁谁先执行。
* synchronzied锁的是调用对象,因为对象都是phone,所以是先执行发短信,再执行打电话
* 不用synchronized修饰的方法不参与锁的抢占
* 所以执行顺序应该是 你好====>发短信=====》打电话
* */
public static void main(String[] args) {
//定义共享资源类
Phone phone = new Phone();
new Thread(()->{
phone.sms();
},"A").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone.call();
},"B").start();
new Thread(()->{
phone.hello();
},"c").start();
}
}
class Phone{//资源类
synchronized void sms(){//发短信
try {
//进来线程先睡五秒钟,这不会释放锁
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"=>发短信");
}
synchronized void call(){//打电话
System.out.println(Thread.currentThread().getName()+"=>打电话");
}
void hello(){
System.out.println(Thread.currentThread().getName()+"=>你好");
}
}
2、synchronized修饰静态方法
package juctest;
import java.util.concurrent.TimeUnit;
public class LockTest2 {
/**
* synchronzied修饰静态方法锁的是类的class模板,同一个类只有一个class模板
* 所以线程A先抢占到锁,所以它先执行,sleep方法不会释放锁,wait方法会释放锁
* 所以执行顺序是发短信=====》打电话
*
* 如果是不同的类,就是其实没有并发问题了,访问的不是同一个资源类,
* 再一个说,两个线程访问不同的类中的static方法,是没有先后的,锁不住的
*
*
* */
public static void main(String[] args) {
//定义共享资源类
Phone2 phone2 = new Phone2();
new Thread(()->{
phone2.sms();
},"A").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone2.call();
},"B").start();
}
}
class Phone2{//资源类
synchronized static void sms(){//发短信
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"=>发短信");
}
synchronized static void call(){//打电话
System.out.println(Thread.currentThread().getName()+"=>打电话");
}
}
package juctest;
import java.util.concurrent.TimeUnit;
public class LockTest3 {
/**
* synchronzied修饰静态方法锁的是类的class模板,同一个类只有一个class模板
* 一个资源类中的两个方法:
* 1、一个静态方法,一个普通方法,一个锁的是class,一个锁的是调用对象,所以两个没有具体的先后顺序(如果同时执行的话)
* 我们这里有sleep(),所以输出 打电话===》发短信
* 2、两个对象同理。
*
* */
public static void main(String[] args) {
//定义共享资源类
Phone3 phone3 = new Phone3();
new Thread(()->{
phone3.sms();
},"A").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone3.call();
},"B").start();
}
}
class Phone3{//资源类
synchronized static void sms(){//发短信
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"=>发短信");
}
synchronized void call(){//打电话
System.out.println(Thread.currentThread().getName()+"=>打电话");
}
}
3、synchronized修饰代码块
package juctest;
import java.util.concurrent.TimeUnit;
public class LockTest4 {
/**
* synchronzied修饰同步代码块锁的是指定的对象
* 这里我们用的是调用方对象的class文件,Phone4唯一的,
* 所以当线程A拿到锁sleep的过程中,那么线程B执行到同步代码块的时候只能等待线程A释放锁
* 所以执行顺序为 发短信=====》打电话
*
*
* 如果我们同步代码块传的对象为new Object(),那么每个线程进来的时候都会锁一个新的对象,
* 所以这种写法是什么都锁不住的,执行结果为 打电话===》发短信
*
* */
public static void main(String[] args) {
//定义共享资源类
Phone4 phone4 = new Phone4();
new Thread(()->{
phone4.sms();
},"A").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone4.call();
},"B").start();
}
}
class Phone4{//资源类
void sms(){//发短信
synchronized (this.getClass()){//new Object()
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"=>发短信");
}
}
void call(){//打电话
synchronized (this.getClass()){//new Object()
System.out.println(Thread.currentThread().getName()+"=>打电话");
}
}
}