1. 问题:两个线程是先打印 发短信 还是 打电话
1.1 代码
package com.lock;
import java.util.concurrent.TimeUnit;
public class Test1 {
public static void main(String[] args) {
Phone phone = new Phone();
new Thread(() -> {
phone.sendSms();
}, "A").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() -> {
phone.call();
}, "B").start();
}
}
class Phone {
public synchronized void sendSms() {
System.out.println("发短信");
}
public synchronized void call() {
System.out.println("打电话");
}
}
1.2 输出 :
发短信
打电话
1.3 结论 :
并不是像表面那样看起来从上到下顺序执行的,而是因为有锁的存在,而此时synchronized 锁的对象是方法的调用者,也就是phone,而两个方法用的是同一个锁,也即谁先拿到谁执行!
2. 问题:两个线程是先打印 发短信 还是 打电话(注:发短信的方法睡3秒)
2.1 代码
package com.lock;
import java.util.concurrent.TimeUnit;
public class Test2 {
public static void main(String[] args) {
Phone phone = new Phone();
new Thread(() -> {
phone.sendSms();
}, "A").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() -> {
phone.call();
}, "B").start();
}
}
class Phone {
public synchronized void sendSms() {
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public synchronized void call() {
System.out.println("打电话");
}
}
2.2 输出
发短信
打电话
2.3 结论
A线程抱着锁去睡了3秒,醒来后发短信,完成后释放锁,接着B线程拿到锁,去打电话。对于同一把锁,谁先拿到谁先执行。
3. 两个线程是先打印 发短信 还是 打电话(注:发短信的方法睡3秒,打电话去掉synchronized 变成普通方法)
3.1 代码
package com.lock;
import java.util.concurrent.TimeUnit;
public class Test3 {
public static void main(String[] args) {
Phone phone = new Phone();
new Thread(() -> {
phone.sendSms();
}, "A").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() -> {
phone.call();
}, "B").start();
}
}
class Phone {
public synchronized void sendSms() {
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public void call() {
System.out.println("打电话");
}
}
3.2 输出
打电话
发短信
3.3 结论
打电话时普通方法,不受锁的影响
4. 两个线程是先打印 发短信 还是 打电话(注:2个对象,2个同步方法,发短信的方法睡3秒)
4.1 代码
package com.lock;
import java.util.concurrent.TimeUnit;
public class Test3 {
public static void main(String[] args) {
Phone phone1 = new Phone();
Phone phone2 = new Phone();
new Thread(() -> {
phone1.sendSms();
}, "A").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() -> {
phone2.call();
}, "B").start();
}
}
class Phone {
public synchronized void sendSms() {
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public synchronized void call() {
System.out.println("打电话");
}
}
4.2 输出
打电话
发短信
4.3 结论
两个对象,两个调用者,也即是两把锁,按时间执行,发短信的方法睡了3秒,所以先输出打电话
5.两个线程是先打印 发短信 还是 打电话(注:1个对象,2个静态同步方法,发短信的方法睡3秒)
5.1 代码
package com.lock;
import java.util.concurrent.TimeUnit;
public class Test3 {
public static void main(String[] args) {
Phone phone = new Phone();
new Thread(() -> {
phone.sendSms();
}, "A").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() -> {
phone.call();
}, "B").start();
}
}
class Phone {
public static synchronized void sendSms() {
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public static synchronized void call() {
System.out.println("打电话");
}
}
5.2 输出
发短信
打电话
5.3 结论
因为static的关系,此时锁的对象是Phone的class对象,而class是全局唯一的,只有1个,故用的是同一把锁
6.两个线程是先打印 发短信 还是 打电话(注:2个对象,2个静态同步方法,发短信的方法睡3秒)
6.1 代码
package com.lock;
import java.util.concurrent.TimeUnit;
public class Test3 {
public static void main(String[] args) {
Phone phone1 = new Phone();
Phone phone2 = new Phone();
new Thread(() -> {
phone1.sendSms();
}, "A").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() -> {
phone2.call();
}, "B").start();
}
}
class Phone {
public static synchronized void sendSms() {
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public static synchronized void call() {
System.out.println("打电话");
}
}
6.2 输出
发短信
打电话
6.3 结论
即使是两个不同的对象,但因为static的关系,此时锁的对象仍是Phone的class对象,而class是全局唯一的,只有1个,故用的是同一把锁
7.两个线程是先打印 发短信 还是 打电话(注:1个对象,1个静态同步方法发短信,1个同步方法打电话,发短信的方法睡3秒)
7.1 代码
package com.lock;
import java.util.concurrent.TimeUnit;
public class Test3 {
public static void main(String[] args) {
Phone phone = new Phone();
new Thread(() -> {
phone.sendSms();
}, "A").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() -> {
phone.call();
}, "B").start();
}
}
class Phone {
public static synchronized void sendSms() {
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public synchronized void call() {
System.out.println("打电话");
}
}
7.2 输出
打电话
发短信
7.3 结论
静态的同步方法(发短信)锁的是 Class 类模板, 普通的同步方法(打电话)锁的是调用者,而发短信睡了3秒,故先输出打电话
8.两个线程是先打印 发短信 还是 打电话(注:2个对象,1个静态同步方法发短信,1个同步方法打电话,发短信的方法睡3秒)
8.1 代码
package com.lock;
import java.util.concurrent.TimeUnit;
public class Test3 {
public static void main(String[] args) {
Phone phone1 = new Phone();
Phone phone2 = new Phone();
new Thread(() -> {
phone1.sendSms();
}, "A").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() -> {
phone2.call();
}, "B").start();
}
}
class Phone {
public static synchronized void sendSms() {
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public synchronized void call() {
System.out.println("打电话");
}
}
8.2 输出
打电话
发短信
8.3 结论
跟7的结论一样,静态的同步方法(发短信)锁的是 Class 类模板, 普通的同步方法(打电话)锁的是调用者,而发短信睡了3秒,故先输出打电话