场景一
import java.util.concurrent.TimeUnit;
/*
* 场景一:sendMsg和call都是同步方法,先打印谁?
* 答案:A-->发短信
* 分析:被synchronized修饰属于同步方法,这里争夺地是同一把锁,谁先调用锁就先执行
* */
public class Lock8 {
public static void main(String[] args) {
Phone phone1 = new Phone();
//Phone phone2 = new Phone();
new Thread(()->{phone1.sendMsg();},"A").start();
//保证线程A先到达Runnable状态,线程B后到达Runnable状态
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{phone1.call();},"B").start();
}
}
class Phone{
public synchronized void sendMsg(){
System.out.println(Thread.currentThread().getName() + "-->发短信");
}
public synchronized void call(){
System.out.println(Thread.currentThread().getName() + "-->打电话");
}
}
场景二
import java.util.concurrent.TimeUnit;
/*
* 场景二:sendMsg和call都是同步方法,不过被先调用的sendMsg方法块内增加了休眠,先打印谁?
* 答案:A-->发短信
* 分析:线程A和线程B争夺地是同一把锁,谁先调用就先执行
* */
public class Lock8 {
public static void main(String[] args) {
Phone phone1 = new Phone();
//Phone phone2 = new Phone();
new Thread(() -> {
phone1.sendMsg();
}, "A").start();
//保证线程A先到达Runnable状态,线程B后到达Runnable状态
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() -> {
phone1.call();
}, "B").start();
}
}
class Phone {
public synchronized void sendMsg() {
//当线程A、B抢夺的不是同一把锁时,sendMsg方法休眠使线程B的call方法先被打印出来
//这里必须保证该休眠与Main方法内的休眠存在差值
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "-->发短信");
}
public synchronized void call() {
System.out.println(Thread.currentThread().getName() + "-->打电话");
}
}
场景三
import java.util.concurrent.TimeUnit;
/*
* 场景三:call方法改为普通方法,sendMsg改为同步方法,先打印谁?
* 答案:B-->打电话
* 分析:线程A在争夺抢锁,线程B和锁无关,虽然线程A被先调用执行,但sendMsg内的休眠使它比call晚了1s
* */
public class Lock8 {
public static void main(String[] args) {
Phone phone1 = new Phone();
//Phone phone2 = new Phone();
new Thread(() -> {
phone1.sendMsg();
}, "A").start();
//保证线程A先到达Runnable状态,线程B后到达Runnable状态
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() -> {
phone1.call();
}, "B").start();
}
}
class Phone {
public synchronized void sendMsg() {
//当线程A、B抢夺的不是同一把锁时,sendMsg方法休眠使线程B的call方法先被打印出来
//这里必须保证该休眠与Main方法内的休眠存在差值
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "-->发短信");
}
public void call() {
System.out.println(Thread.currentThread().getName() + "-->打电话");
}
}
场景四
import java.util.concurrent.TimeUnit;
/*
* 场景四:新建另一个对象phone2,两个线程分别使用两个对象调用方法,先打印谁?
* 答案:B-->打电话
* 分析:synchronized锁的是调用的对象,这里有两把锁,线程B不必等待线程A释放锁即可执行call方法
* */
public class Lock8 {
public static void main(String[] args) {
Phone phone1 = new Phone();
Phone phone2 = new Phone();
new Thread(() -> {
phone1.sendMsg();
}, "A").start();
//保证线程A先到达Runnable状态,线程B后到达Runnable状态
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() -> {
phone2.call();
}, "B").start();
}
}
class Phone {
public synchronized void sendMsg() {
//当线程A、B抢夺的不是同一把锁时,sendMsg方法休眠使线程B的call方法先被打印出来
//这里必须保证该休眠与Main方法内的休眠存在差值
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "-->发短信");
}
public synchronized void call() {
System.out.println(Thread.currentThread().getName() + "-->打电话");
}
}
场景五
import java.util.concurrent.TimeUnit;
/*
* 场景五:两个方法前面用static synchronized修饰,先打印谁?
* 答案:A-->发短信
* 分析:static synchronized锁的是调用的类,所以这里还是同一把锁,线程B必须等待线程A释放锁才能执行call方法
* */
public class Lock8 {
public static void main(String[] args) {
Phone phone1 = new Phone();
//Phone phone2 = new Phone();
new Thread(() -> {
phone1.sendMsg();
}, "A").start();
//保证线程A先到达Runnable状态,线程B后到达Runnable状态
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() -> {
phone1.call();
}, "B").start();
}
}
class Phone {
public static synchronized void sendMsg() {
//当线程A、B抢夺的不是同一把锁时,sendMsg方法休眠使线程B的call方法先被打印出来
//这里必须保证该休眠与Main方法内的休眠存在差值
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "-->发短信");
}
public static synchronized void call() {
System.out.println(Thread.currentThread().getName() + "-->打电话");
}
}
场景六
import java.util.concurrent.TimeUnit;
/*
* 场景六:一个方法前面用static synchronized修饰,另一个前面用synchronized修饰,先打印谁?
* 答案:B-->打电话
* 分析:sendMsg方法锁的是类,call方法锁的是对象,这里有两把锁
* */
public class Lock8 {
public static void main(String[] args) {
Phone phone1 = new Phone();
//Phone phone2 = new Phone();
new Thread(() -> {
phone1.sendMsg();
}, "A").start();
//保证线程A先到达Runnable状态,线程B后到达Runnable状态
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() -> {
phone1.call();
}, "B").start();
}
}
class Phone {
public static synchronized void sendMsg() {
//当线程A、B抢夺的不是同一把锁时,sendMsg方法休眠使线程B的call方法先被打印出来
//这里必须保证该休眠与Main方法内的休眠存在差值
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "-->发短信");
}
public static void call() {
System.out.println(Thread.currentThread().getName() + "-->打电话");
}
}
场景七
import java.util.concurrent.TimeUnit;
/*
* 场景七:两个方法前面都用static synchronized修饰,同时新建另外一个对象phone2,先打印谁?
* 答案:A-->发短信
* 分析:这里锁的是类,所以两个对象争夺地还是同一把锁
* */
public class Lock8 {
public static void main(String[] args) {
Phone phone1 = new Phone();
Phone phone2 = new Phone();
new Thread(() -> {
phone1.sendMsg();
}, "A").start();
//保证线程A先到达Runnable状态,线程B后到达Runnable状态
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() -> {
phone2.call();
}, "B").start();
}
}
class Phone {
public static synchronized void sendMsg() {
//当线程A、B抢夺的不是同一把锁时,sendMsg方法休眠使线程B的call方法先被打印出来
//这里必须保证该休眠与Main方法内的休眠存在差值
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "-->发短信");
}
public static synchronized void call() {
System.out.println(Thread.currentThread().getName() + "-->打电话");
}
}
场景八
import java.util.concurrent.TimeUnit;
/*
* 场景八:一个方法前面用static synchronized修饰,另一个前面用synchronized修饰,两个对象分别调用不同方法,先打印谁?
* 答案:B-->打电话
* 分析:用static synchronized修饰锁的是类,用用synchronized修饰锁的是对象,所以两个对象争夺地是不同的两把锁
* */
public class Lock8 {
public static void main(String[] args) {
Phone phone1 = new Phone();
Phone phone2 = new Phone();
new Thread(() -> {
phone1.sendMsg();
}, "A").start();
//保证线程A先到达Runnable状态,线程B后到达Runnable状态
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() -> {
phone2.call();
}, "B").start();
}
}
class Phone {
public static synchronized void sendMsg() {
//当线程A、B抢夺的不是同一把锁时,sendMsg方法休眠使线程B的call方法先被打印出来
//这里必须保证该休眠与Main方法内的休眠存在差值
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "-->发短信");
}
public synchronized void call() {
System.out.println(Thread.currentThread().getName() + "-->打电话");
}
}
总结
- 对于八锁问题,首先明白Main方法内休眠和先调用方法内休眠的不同作用,这是前提条件;
- 被
synchronized
修饰锁的是调用的对象,被static synchronized
修饰锁的是调用的类;
- 不管两个线程执行地是不是一个对象的方法,只要争夺地是同一把锁就按线程顺序执行。