八锁现象
如何判断锁的是谁?
首先锁只会锁住两个东西:对象、Class
问题1
两个同步方法,先执行发短信还是打电话
public class demo1 {
public static void main(String[] args) throws InterruptedException {
Phone phone = new Phone();
new Thread(() -> {phone.sendMs();}).start();
TimeUnit.SECONDS.sleep(1);
new Thread(() -> {phone.call();}).start();
}
}
class Phone {
public synchronized void sendMs() {
System.out.println("发短信");
}
public synchronized void call() {
System.out.println("打电话");
}
}
输出结果:
发短信
打电话
问题2
我们再来看:我们让发短信 延迟4s
public class demo1 {
public static void main(String[] args) throws InterruptedException {
Phone phone = new Phone();
new Thread(() -> {
try {
phone.sendMs();
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
TimeUnit.SECONDS.sleep(1);
new Thread(() -> { phone.call(); }).start();
}
}
class Phone {
public synchronized void sendMs() throws InterruptedException {
TimeUnit.SECONDS.sleep(4);
System.out.println("发短信");
}
public synchronized void call() {
System.out.println("打电话");
}
}
现在结果是什么呢?
结果:还是先发短信,然后再打电话
为什么?原因:并不是顺序执行,而是synchronized锁住的对象是方法的调用者!对于两个方法锁的都是一个调用者,谁先拿到锁谁先执行,另外一个等待
问题3
加一个普通方法
public class demo1 {
public static void main(String[] args) throws InterruptedException {
Phone phone = new Phone();
new Thread(() -> {
try {
phone.sendMs();
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
TimeUnit.SECONDS.sleep(1);
new Thread(() -> { phone.hello(); }).start();
}
}
class Phone {
public synchronized void sendMs() throws InterruptedException {
TimeUnit.SECONDS.sleep(4);
System.out.println("发短信");
}
public synchronized void call() {
System.out.println("打电话");
}
public void hello() {
System.out.println("hello");
}
}
输出结果:
hello
发短信
原因:hello没有锁,不是同步方法,是一个普通方法,不受synchronized锁的影响,不用等待锁的释放
问题4
如果我们使用的是两个对象,一个调用发短信,一个调用打电话,那么整个顺序是怎么样的呢?
public class demo1 {
public static void main(String[] args) throws InterruptedException {
Phone phone1 = new Phone();
Phone phone2 = new Phone();
new Thread(() -> {
try {
phone1.sendMs();
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
TimeUnit.SECONDS.sleep(1);
new Thread(() -> { phone2.call(); }).start();
}
}
class Phone {
public synchronized void sendMs() throws InterruptedException {
TimeUnit.SECONDS.sleep(4);
System.out.println("发短信");
}
public synchronized void call() {
System.out.println("打电话");
}
public void hello() {
System.out.println("hello");
}
}
输出结果:
打电话
发短信
原因:synchronized锁了两个不同的调用者、两把锁,不会出现等待的情况,发短信睡了4s,所以先执行打电话
问题5、6
如果我们把synchronized的方法加上static变成静态方法!那么顺序又是怎么样的呢?
(1)我们先来使用一个对象调用两个方法
public class demo1 {
public static void main(String[] args) throws InterruptedException {
Phone phone = new Phone();
new Thread(() -> {
try {
phone.sendMs();
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
TimeUnit.SECONDS.sleep(1);
new Thread(() -> { phone.call(); }).start();
}
}
class Phone {
public static synchronized void sendMs() throws InterruptedException {
TimeUnit.SECONDS.sleep(4);
System.out.println("发短信");
}
public static synchronized void call() {
System.out.println("打电话");
}
public void hello() {
System.out.println("hello");
}
}
输出结果:
发短信
打电话
(2)如果我们使用两个对象调用两个方法
public class demo1 {
public static void main(String[] args) throws InterruptedException {
Phone phone1 = new Phone();
Phone phone2 = new Phone();
new Thread(() -> {
try {
phone1.sendMs();
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
TimeUnit.SECONDS.sleep(1);
new Thread(() -> { phone2.call(); }).start();
}
}
class Phone {
public static synchronized void sendMs() throws InterruptedException {
TimeUnit.SECONDS.sleep(4);
System.out.println("发短信");
}
public static synchronized void call() {
System.out.println("打电话");
}
public void hello() {
System.out.println("hello");
}
}
输出结果:
发短信
打电话
原因是什么呢?为什么加了static就始终前面一个对象先执行呢!为什么后面会等待呢?
原因是:加了static是静态方法,而静态方法类一加载就有了,synchronized锁的是class!而两个方法都用static修饰就只有一个锁,不管多少个对象,谁先拿到这个锁就先执行,其他的进程等待!
问题7
如果我们使用一个静态同步方法、一个同步方法、一个对象调用顺序是什么?
public class demo1 {
public static void main(String[] args) throws InterruptedException {
Phone phone1 = new Phone();
new Thread(() -> {
try {
phone1.sendMs();
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
TimeUnit.SECONDS.sleep(1);
new Thread(() -> { phone1.call(); }).start();
}
}
class Phone {
public static synchronized void sendMs() throws InterruptedException {
TimeUnit.SECONDS.sleep(4);
System.out.println("发短信");
}
public synchronized void call() {
System.out.println("打电话");
}
public void hello() {
System.out.println("hello");
}
}
输出结果:
打电话
发短信
原因:因为一个锁的是Class类的模板,一个锁的是对象的调用者。所以不存在等待,直接运行
问题8
如果我们使用一个静态同步方法、一个同步方法、两个对象调用顺序是什么?
public class demo1 {
public static void main(String[] args) throws InterruptedException {
Phone phone1 = new Phone();
Phone phone2 = new Phone();
new Thread(() -> {
try {
phone1.sendMs();
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
TimeUnit.SECONDS.sleep(1);
new Thread(() -> { phone2.call(); }).start();
}
}
class Phone {
public static synchronized void sendMs() throws InterruptedException {
TimeUnit.SECONDS.sleep(4);
System.out.println("发短信");
}
public synchronized void call() {
System.out.println("打电话");
}
public void hello() {
System.out.println("hello");
}
}
输出结果:
打电话
发短信
原因:两把锁锁的不是一个东西,一个是class一个是对象
思考:只有两把锁作用到一个class或者对象才会锁的住??、