锁的定义是什么?锁的对象还是Class对象?
示例1:
/**
* @author
* @Date 2022/7/11
* @apiNote
*/
public class eightLock {
public static void main(String[] args) {
Person person=new Person();
new Thread(()->{
try {
TimeUnit.SECONDS.sleep(3);//延迟3s
} catch (InterruptedException e) {
e.printStackTrace();
}
person.eat();
},"A").start();
new Thread(()->{
person.drink();
},"B").start();
}
static class Person{
public synchronized void eat(){
System.out.println("先吃饭");
}
public synchronized void drink(){
System.out.println("先喝水");
}
}
}
执行:
**分析:**sychronized锁的是方法的调用者,两个方法用的是同一个对象,谁先拿到就谁先执行,示例1由于线程A调用eat()的方法前延迟了3s,所以线程B抢到了资源,先行调用了drink().
示例2:
package com.wang.eight;
import java.util.concurrent.TimeUnit;
/**
* @author wangchangjun
* @Date 2022/7/11
* @apiNote
*/
public class eightLock {
public static void main(String[] args) {
Person person=new Person();
new Thread(()->{
person.eat();
},"A").start();
new Thread(()->{
person.drink();
},"B").start();
}
static class Person{
public synchronized void eat(){
try {
TimeUnit.SECONDS.sleep(3);//延迟3s
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("先吃饭");
}
public synchronized void drink(){
System.out.println("先喝水");
}
}
}
结果:
**分析:**示例2将延迟加到了eat()中,点击运行后,线程A拿到了资源,进入eat()中,锁住方法,3s后打印信息,eat()执行完毕,线程B执行。
示例3
/**
* @author
* @Date 2022/7/11
* @apiNote
*/
public class eightLock {
public static void main(String[] args) {
Person person=new Person();
new Thread(()->{
try {
TimeUnit.SECONDS.sleep(2);//延迟2s
} catch (InterruptedException e) {
e.printStackTrace();
}
person.eat();
},"A").start();
new Thread(()->{
person.drink();
},"B").start();
}
static class Person{
public synchronized void eat(){
try {
TimeUnit.SECONDS.sleep(2);//延迟2s
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("先吃饭");
}
public synchronized void drink(){
System.out.println("先喝水");
}
}
}
结果:
**分析:**由于线程A延迟原因,线程B抢到资源,调用drink(),2s后,线程A执行走入eat(),再次延迟2s后,打印信息。
示例4:
package com.wang.eight;
import java.util.concurrent.TimeUnit;
/**
* @author wangchangjun
* @Date 2022/7/11
* @apiNote
*/
public class eightLock {
public static void main(String[] args) {
Person person=new Person();
new Thread(()->{
person.eat();
},"A").start();
new Thread(()->{
person.play();
},"B").start();
}
static class Person{
public synchronized void eat(){
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("先吃饭");
}
public synchronized void drink(){
System.out.println("先喝水");
}
public void play(){
System.out.println("先玩耍");
}
}
}
结果:
分析:由于play()是普通方法,不受锁的影响,所以根据先打印play()。
示例5:增加两个对象,两个线程分别调用
/**
* @author
* @Date 2022/7/11
* @apiNote
*/
public class eightLock {
public static void main(String[] args) {
Person person=new Person();
Person person1=new Person();
new Thread(()->{
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
person.eat();
},"A").start();
new Thread(()->{
person1.drink();
},"B").start();
}
static class Person{
public synchronized void eat(){
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("先吃饭");
}
public synchronized void drink(){
System.out.println("先喝水");
}
}
}
结果:
分析:
由于线程A延迟,线程B先执行。2s+2s后打印信息
示例6:增加两个静态方法
/**
* @author
* @Date 2022/7/11
* @apiNote
*/
public class eightLock {
public static void main(String[] args) {
Person person=new Person();
new Thread(()->{
person.eat();
},"A").start();
new Thread(()->{
person.drink();
},"B").start();
}
static class Person{
public static synchronized void eat(){
System.out.println("先吃饭");
}
public static synchronized void drink(){
System.out.println("先喝水");
}
结果:
分析:
static静态方法类一加载就有了,所以锁的是Class对象,所以按顺序加载的是eat()
示例6
,基于示例5,增加两对象
结果:
分析:
两个对象的Class类模板只有一个,static锁的是class模板
示例7
一个静态同步方法,一个普通方法,一个对象调用
package com.wang.eight;
import java.util.concurrent.TimeUnit;
/**
* @author wangchangjun
* @Date 2022/7/11
* @apiNote
*/
public class eightLock {
public static void main(String[] args) {
Person person=new Person();
new Thread(()->{
person.eat();
},"A").start();
new Thread(()->{
person.drink();
},"B").start();
}
static class Person{
public static synchronized void eat(){
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("先吃饭");
}
public synchronized void drink(){
System.out.println("先喝水");
}
}
}
结果:
分析:
静态同步锁的是Class模板对象,普通同步方法锁的是调用对象,互不影响,按顺序调用。
示例8
基于示例7,增加两个对象
结果:
分析
与例7相同,即使两个对象分别调用,但是锁的对象不同,一个是class对象,一个是调用者对象。
小结
锁的对象无外乎两种,一个是new出来的具体对象,另一个就是唯一的Class模板。