8锁现象

8锁现象:深刻理解锁

1.多个线程使用一把锁

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Test {
    public static void main(String[] args) {
        Phone phone = new Phone();

        new Thread(()->{
            phone.sendSms();
        },"A").start();

        //使主线程sleep一秒,保证第一个线程先执行
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(()->{
            phone.call();
        },"B").start();
    }

}
class Phone{
    public synchronized void sendSms(){
        //synchronized 锁的对象是方法的调用者!
        //两个方法用的是同一个锁,谁先拿到谁执行!
        System.out.println("发送短信");
    }
    public synchronized void call(){
        System.out.println("打电话");
    }
}

  • 执行结果
发送短信
打电话

2.多个线程使用同一把锁(线程阻塞)

并不会因为第一个线程里有阻塞而影响执行顺序

  • 根据调用顺序执行
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Test {
    public static void main(String[] args) {
        Phone phone = new Phone();

        new Thread(()->{
            phone.sendSms();
        },"A").start();

        //使主线程sleep一秒,保证第一个线程先执行
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(()->{
            phone.call();
        },"B").start();
    }

}
class Phone{
    public synchronized void sendSms(){
        //synchronized 锁的对象是方法的调用者!
        //两个方法用的是同一个锁,谁先拿到谁执行!
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("发送短信");
    }
    public synchronized void call(){
        System.out.println("打电话");
    }
}
  • 执行结果
发送短信
打电话

3.多个线程部分有锁

多个线程,部分线程有锁,两者之间不存在竞争同一把锁的情况

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Test {
    public static void main(String[] args) {
        Phone phone = new Phone();

        new Thread(()->{
            phone.sendSms();
        },"A").start();

        //使主线程sleep一秒,保证第一个线程先执行

        new Thread(()->{
            try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
            phone.call();
        },"B").start();

        new Thread(()->{
            phone.hello();
        },"C").start();
    }

}
class Phone{
    public synchronized void sendSms(){
        //synchronized 锁的对象是方法的调用者!
        System.out.println("发送短信");
    }
    public synchronized void call(){
        System.out.println("打电话");
    }
    // 这里没有锁!不是同步方法,不受锁的影响
    public void hello(){
        System.out.println("hello");
    }
}

  • 执行结果
发送短信
hello
打电话

4.多个线程使用多把锁

  • 被 synchronized 修饰的方法,锁的对象是方法的调用者;
  • 调用者不同,它们之间用的不是同一个锁,相互之间没有关系。
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Test {
    public static void main(String[] args) {
        Phone phone1 = new Phone();
        Phone phone2 = new Phone();

        new Thread(()->{
            phone1.sendSms();
        },"A").start();

        new Thread(()->{
            try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
            phone2.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("打电话");
    }

}

  • 执行结果
打电话
发送短信

5.Class锁(多个线程使用一个对象)

  • 线程之间顺序执行

被 synchronized 和 static 同时修饰的方法,锁的对象是类的 class 对象,是唯一的一把锁。线程之间是顺序执行。

锁Class和锁对象的区别:

1、Class 锁 ,类模版,只有一个;

2、对象锁 , 通过类模板可以new 多个对象。

如果全部都锁了Class,那么这个类下的所有对象都具有同一把锁。

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Test {
    public static void main(String[] args) {
        Phone phone1 = new Phone();

        new Thread(()->{
            phone1.sendSms();
        },"A").start();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(()->{
             phone1.call();
        },"B").start();

    }

}
class Phone{
    // synchronized 锁的对象是方法的调用者!
    // static 静态方法
    // 类一加载就有了!锁的是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("打电话");
    }

}

  • 执行结果
发送短信
打电话

6.Class锁(多个线程使用多个对象)

被 synchronized 修饰 和 static 修饰的方法,锁的对象是类的 class 对象,是唯一的一把锁。

Class锁是唯一的,所以多个对象使用的也是同一个Class锁。

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Test {
    public static void main(String[] args) {
         // 两个对象的Class类模板只有一个,static,锁的是Class
        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{
    // synchronized 锁的对象是方法的调用者!
    // static 静态方法
    // 类一加载就有了!锁的是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("打电话");
    }

}

  • 执行结果
发送短信
打电话

7.Class锁和对象锁(多个线程使用一个对象)

  • 类里面一个方法为静态,一个非静态

被 synchronized和static修饰的方法,锁的对象是类的class对象!唯一的同一把锁;

只被synchronized修饰的方法,是普通锁(如对象锁),不是Class锁,所以进程之间执行顺序互不干扰。

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Test {
    public static void main(String[] args) {
        Phone phone1 = new Phone();

        new Thread(()->{
            phone1.sendSms();
        },"A").start();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(()->{
             phone1.call();
        },"B").start();

    }

}
class Phone{
    // synchronized 锁的对象是方法的调用者!
    // static 静态方法
    // 类一加载就有了!锁的是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("打电话");
    }

}

  • 执行结果
打电话
发送短信

8.Class锁与对象锁(多个线程使用多个对象)

被 synchronized和static修饰的方法,锁的对象是类的class对象!唯一的同一把锁;

只被synchronized修饰的方法,是普通锁(如对象锁),不是Class锁,所以进程之间执行顺序互不干扰。

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Test {
    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{
    // synchronized 锁的对象是方法的调用者!
    // static 静态方法
    // 类一加载就有了!锁的是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("打电话");
    }

}

  • 执行结果
打电话
发送短信

9.总结

  1. 锁是一种竞争机制,一个方法加锁,一个方法没有加锁,那么普通方法就会先运行,因为它不要去竞争!
  2. 被synchornized修饰的同步方法,锁的对象是方法的调用者。谁先调用,谁先执行!
  3. 被synchronized修饰和static修饰的方法,锁的对象是类的class对象,唯一的!
# Java 

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×