java 8锁问题
一个类,里面有静态同步方法、普通同步方法、普通方法等,通过分析不同对象、不同线程,确定锁的是谁
1.标准情况下,一个对象,两个线程
public class Test01 {
public static void main(String[] args) {
Phone phone = new Phone();
//线程A
new Thread(()->{
phone.sendSms();
},"A").start();
//加个延迟,确保线程A先拿到锁
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
//线程B
new Thread(()->{
phone.call();
},"B").start();
}
}
class Phone{
//synchronized锁的对象是方法的调用者
//两个方法用的同一个锁,谁先拿到谁执行
public synchronized void sendSms(){
System.out.println("发短信");
}
public synchronized void call(){
System.out.println("打电话");
}
}
先执行发短信还是先执行打电话?
答案:先执行打印发短信。因为此时synchronized锁的是方法的调用者,虽然有两个线程,但是是一个对象,一个锁,线程A拿到锁之后,如果不释放,线程B就无法获得锁。
2.sendSms方法延迟4秒,一个对象,两个线程
public class Test01 {
public static void main(String[] args) {
Phone phone = new Phone();
//线程A
new Thread(()->{
phone.sendSms();
},"A").start();
//加个延迟,确保线程A先拿到锁
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
//线程B
new Thread(()->{
phone.call();
},"B").start();
}
}
class Phone{
//synchronized锁的对象是方法的调用者
//两个方法用的同一个锁,谁先拿到谁执行
public synchronized void sendSms(){
try {
TimeUnit.SECONDS.sleep(4);//延时四秒
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public synchronized void call(){
System.out.println("打电话");
}
}
先打印发短信还是打电话?
答案:先执行打印发短信。和上面一样,两个线程同一把锁,线程B要等线程A将锁释放
3.将打电话修改为普通方法(不是同步方法),一个对象,两个线程
public class Test02 {
public static void main(String[] args) {
Phone phone1 = new Phone();
//线程A
new Thread(()->{
phone.sendSms();
},"A").start();
//加个延迟,确保线程A先开始
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
//线程B
new Thread(()->{
phone.call();
},"B").start();
}
}
class Phone{
public synchronized void sendSms(){
try {
TimeUnit.SECONDS.sleep(4);//延时四秒
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
//这里没有锁,不是同步方法
public void call(){
System.out.println("打电话");
}
}
先执行发短信还是打电话?
答案:打电话。因为线程A虽然先开始而且拿到锁,但是执行sendSms方法,有四秒的延迟,而线程B执行的不是同步方法,不需要等待线程A释放锁,所以会在线程A的四秒延迟结束之前执行完。(锁的还是对象)
4.两个对象,两个线程,两个同步方法
public class Test02 {
public static void main(String[] args) {
Phone phone1 = new Phone();
Phone phone2 = new Phone();
//线程A
new Thread(()->{
phone1.sendSms();
},"A").start();
//加个延迟,确保线程A先开始
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
//线程B
new Thread(()->{
phone2.call();
},"B").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("打电话");
}
}
先执行发短信还是打电话?
答案:打电话。因为线程A虽然先开始而且拿到锁,但是执行sendSms方法,有四秒的延迟,而线程B与线程A不是同一个对象,不需要等待线程A释放锁,所以会在线程A的四秒延迟结束之前执行完先打印。(锁的是方法的调用者,两个对象两个锁)
5.一个对象,两个线程,两个静态同步方法
public class Test01 {
public static void main(String[] args) {
Phone phone = new Phone();
//线程A
new Thread(()->{
phone.sendSms();
},"A").start();
//加个延迟,确保线程A先拿到锁
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
//线程B
new Thread(()->{
phone.call();
},"B").start();
}
}
class Phone{
//静态方法,类一加载就有了,所以静态同步方法锁的是Class类
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("打电话");
}
}
先执行发短信还是打电话?
答案:发短信。因为静态同步方法锁的是Class类,两个线程同一把锁,A先拿到锁之后,B要等A执行完释放锁
6.两个对象,两个线程,两个静态同步方法
public class Test01 {
public static void main(String[] args) {
Phone phone1 = new Phone();
Phone phone2 = new Phone();
//线程A
new Thread(()->{
phone1.sendSms();
},"A").start();
//加个延迟,确保线程A先拿到锁
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
//线程B
new Thread(()->{
phone2.call();
},"B").start();
}
}
class Phone{
//静态方法,类一加载就有了,所以静态同步方法锁的是Class类
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("打电话");
}
}
先执行发短信还是打电话?
答案:发短信。和上面原因一样,静态同步方法锁的是Class类,虽然两个线程中是两个不同的对象,但是Class是唯一的。所以两个线程还是同一把锁,A先拿到锁之后,B要等A执行完释放锁。
$$
$$
7.一个对象,两个线程,一个静态同步方法,一个普通同步方法
public class Test01 {
public static void main(String[] args) {
Phone phone = new Phone();
//线程A
new Thread(()->{
phone.sendSms();
},"A").start();
//加个延迟,确保线程A先拿到锁
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
//线程B
new Thread(()->{
phone.call();
},"B").start();
}
}
class Phone{
//静态方法,类一加载就有了,所以静态同步方法锁的是Class类
public static synchronized void sendSms(){
try {
TimeUnit.SECONDS.sleep(4);//延时四秒
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
//锁的是方法的调用者
public synchronized void call(){
System.out.println("打电话");
}
}
先执行发短信还是打电话?
答案:打电话。因为第一个锁的是Class,第二个锁的是方法的调用者,也就是new出来的对象。所以两个线程中虽然是同一个对象,但是需要的不是同一把锁,所以线程B不需要等待线程A释放锁。而线程A有四秒延迟,所以先打印打电话。
8.两个对象,两个线程,一个静态同步方法,一个普通同步方法
public class Test01 {
public static void main(String[] args) {
Phone phone1 = new Phone();
Phone phone2 = new Phone();
//线程A
new Thread(()->{
phone1.sendSms();
},"A").start();
//加个延迟,确保线程A先拿到锁
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
//线程B
new Thread(()->{
phone2.call();
},"B").start();
}
}
class Phone{
//静态方法,类一加载就有了,所以静态同步方法锁的是Class类
public static synchronized void sendSms(){
try {
TimeUnit.SECONDS.sleep(4);//延时四秒
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public synchronized void call(){
System.out.println("打电话");
}
}
先执行发短信还是打电话?
答案:打电话。元音和上面一题一样,两个线程中需要的不是同一把锁,所以线程B不需要等待线程A释放锁。而线程A有四秒延迟,所以先打印打电话。