8锁就是8个锁的问题,直接探究出到底锁的是谁:下面看题和结果就可以了。
题的情况很简单,就是一个Phone类,里面有打电话和发短信俩方法,答案就是先发短信还是先打电话即可:
问题1:正常情况下,谁会先输出出来
package lock8;
import java.util.concurrent.TimeUnit;
//1、正常情况下,谁会先输出出来
public class Test1 {
public static void main(String[] args) {
Phone phone = new Phone();
new Thread(()->{phone.sendSms();}).start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{phone.call();}).start();
}
}
class Phone{
public synchronized void sendSms(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发了一波短信");
}
public synchronized void call(){
System.out.println("打了一波电话");
}
}
答案:
发了一波短信
打了一波电话
结论:synchronized锁的是当前调用方法的对象,因为只有一个对象,所以只有当当前对象先执行的方法走完才会去走其他方法。
问题2:和方法1一样,但是对象变成了两个,调用两个对象的不同方法
package lock8;
import java.util.concurrent.TimeUnit;
//2、和方法1一样,但是对象变成了两个,调用两个对象的不同方法
public class Test2 {
public static void main(String[] args) {
Phone2 phone = new Phone2();
Phone2 phone2 =new Phone2();
new Thread(()->{phone.sendSms();}).start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{phone2.call();}).start();
}
}
class Phone2{
public synchronized void sendSms(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发了一波短信");
}
public synchronized void call(){
System.out.println("打了一波电话");
}
}
结果:
打了一波电话
发了一波短信
结论:锁的是对象,因为是不同的两个对象,所以并不受锁的影响。
问题3:在2的基础上,增加一个不受锁的方法,谁先执行?
package lock8;
import java.util.concurrent.TimeUnit;
//2、和方法1一样,但是对象变成了两个,调用两个对象的不同方法
public class Test3 {
public static void main(String[] args) {
Phone3 phone = new Phone3();
new Thread(()->{phone.sendSms();}).start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{phone.hello();}).start();
}
}
class Phone3{
public synchronized void sendSms(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发了一波短信");
}
public synchronized void call(){
System.out.println("打了一波电话");
}
public void hello(){
System.out.println("说了句hello");
}
}
答案:
说了句hello
发了一波短信
结论:因为锁的是对象,然而hello并不在锁里,所以可先执行。
问题4:如果我们锁的两个方法有static关键字呢?
package lock8;
import java.util.concurrent.TimeUnit;
//2、如果我们锁的两个方法有static关键字呢?
public class Test4 {
public static void main(String[] args) {
Phone4 phone = new Phone4();
new Thread(()->{phone.sendSms();}).start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{phone.call();}).start();
}
}
class Phone4{
public static synchronized void sendSms(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发了一波短信");
}
public static synchronized void call(){
System.out.println("打了一波电话");
}
}
答案:跟锁对象的情况一样
发了一波短信
打了一波电话
结论:此时并不能得出什么结果,但是可以知道此时跟锁对象的情况是一样的。结合问题5我们再来总计。
问题5:我们创造两个对象来分别使用两个锁住的静态方法
package lock8;
import java.util.concurrent.TimeUnit;
//2、如果我们锁的两个方法有static关键字呢?
public class Test5 {
public static void main(String[] args) {
Phone5 phone = new Phone5();
Phone5 phone5=new Phone5();
new Thread(()->{phone.sendSms();}).start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{phone5.call();}).start();
}
}
class Phone5{
public static synchronized void sendSms(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发了一波短信");
}
public static synchronized void call(){
System.out.println("打了一波电话");
}
}
结果:
发了一波短信
打了一波电话
结论:带上static后,锁住的明显就是class,即对应的类,因为如果是对象的话,那么会先打电话再发短信。
问题6:在5的基础上加上一个普通方法呢?
package lock8;
import java.util.concurrent.TimeUnit;
//2、如果我们锁的两个方法有static关键字呢?
public class Test6 {
public static void main(String[] args) {
Phone6 phone = new Phone6();
Phone6 phone5=new Phone6();
new Thread(()->{phone.sendSms();}).start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{phone5.call();}).start();
new Thread(()->{phone5.hello();}).start();
}
}
class Phone6{
public static synchronized void sendSms(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发了一波短信");
}
public static synchronized void call(){
System.out.println("打了一波电话");
}
public void hello(){
System.out.println("说了句hello");
}
}
结果:
说了句hello
发了一波短信
打了一波电话
结论:不受锁影响的方法,不管是锁对象还是锁的类,都不会被影响,都是正常输出。
总结:
普通带锁方法:锁对象,同一对象下的才按顺序执行,如果是同一个类下的不同对象则不受影响。
普通不带锁方法:不受任何影响。
静态带锁方法:锁类,同一个类下的所有对象的所有带锁方法都得按顺序执行。