synchronized使用

synsynchronized的使用方法:
1、synchronized修饰方法

(1)synchronized修饰非静态方法: 锁的是方法的调用者

import java.util.concurrent.TimeUnit;
class Data {

    /*synchronized修饰非静态方法,锁的是即方法的调用者,即
       调用func1方法的对象*/
    public synchronized void func1() {
        try {
            TimeUnit.SECONDS.sleep(3);//休眠3秒
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("1....");
    }

    public synchronized void func2() {
        System.out.println("2....");
    }

}

Test1:

public class Test1 {
    public static void main(String[] args) {
       Data data=new Data();
        new  Thread(()->{
            data.func1();
        }).start();
        new  Thread(()->{
            data.func2();
        }).start();
    }
}

结果为:
在这里插入图片描述
在上面的代码中,由于synchronized修饰非静态方法:,锁的是方法的调用者;
所以 在本代码中锁的是Data类的对象,不同的Data对象,有不同的锁,但是此代码中只有一个data对象,第一个线程执行的是data.fun1()方法,第二个线程执行的是data.fun2()方法;

所以当第一个线程执行data.fun1()方法,获取到data对象的锁之后,执行data.fun1()方法,第二个线程获取不到data对象的锁,所以第二个线程中的方法data.fun2()方法无法执行;只有当第一个线程执行完毕(data.fun1()方法执行完),释放了data锁之后,第二个线程才能获取到data的锁,执行data.fun2()方法;

Test2:

public class Test1 {

    public static void main(String[] args) {

        Data data = new Data();
        Data data2 = new Data();
        new Thread(() -> {
            data.func1();
        }).start();
        new Thread(() -> {
            data2.func2();
        }).start();
    }
}

结果为:

在这里插入图片描述
在上面的代码中,由于synchronized修饰非静态方法:,锁的是方法的调用者;
所以锁的是Data类的对象,不同的Data对象,有不同的锁,此代码中有两个Data对象:data,data2;

所以当第一个线程获取到data对象的锁之后,执行data.fun1()方法;第二个线程执行的是data2.fun2()方法,其与第一个线程获取的不是同一个对象的锁,所以也能与第一个线程同时执行,但fun1()方法中,线程休眠了3秒,所以结果先输出2,再输出1;

(2)synchronized修饰静态方法:锁的是class本身

class Data2 {
    /*synchronized修饰静态方法,锁的是class本身,本代码中
        锁的是Data2这个类本身,锁定的不是对象*/
    public synchronized static void func1() {
        try {
            TimeUnit.SECONDS.sleep(3);//休眠3秒
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("1....");
    }

    public synchronized static void func2() {

        System.out.println("2....");
    }
  
}

Test1:

public class Test2 {

    public static void main(String[] args) {
        Data2 data1=new Data2();
        new  Thread(()->{
            data1.func1();
        }).start();
        new  Thread(()->{
            data1.func2();
        }).start();
    }
}

结果为:
在这里插入图片描述
上面的代码中,由于synchronized修饰静态方,:锁的是class本身;

所以第一个线程执行data1.func1()方法,获取到了Data类的锁;而第二个线程中执行的方法是data1.func2()方法,但因为第一个线程已经获取了Data类的锁,所以无法获取锁,只有当第一个线程执行完data1.func1()方法之后,释放了Data类的锁,第二个线程才能运行执行获取到Data类的锁,执行data1.func2()方法;

Test2:

public class Test2 {
    public static void main(String[] args) {
        Data2 data1=new Data2();
        Data2 data2=new Data2();
        new  Thread(()->{
            data1.func1();
        }).start();
        new  Thread(()->{
            data2.func2();
        }).start();
    }
}

结果为:
在这里插入图片描述
在上面的代码中,synchronized修饰的是静态方法(static修饰的方法),则锁的是class本身;
所以在本代码中,锁的是Data.class这个类对象,由于一个类只有一个class对象,所以不管该类有几个实例对象,当一个线程获取该类的锁之后,其他线程就无法获取该类的锁了,只有当上一个线程释放了锁之后,其他线程才能获取这个类的锁,执行方法

2、synchronized修饰代码块

(1)synchronized(类对象)即synchronized(class):锁的是同一个类

class Data3{
    public   void func1(Integer num) {
        synchronized (Data3.class) {//锁的是同一个类
            System.out.println("start....");
            try {
                TimeUnit.SECONDS.sleep(3);//休眠3秒
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("end....");
        }
    }
}

Test:

import java.util.concurrent.TimeUnit;

public class Test3 {
    public static void main(String[] args) {

        Data3 data=new Data3();
        for(int i=0;i<5;i++){
            Integer num=Integer.valueOf(i);
            new Thread(()->{
            data.func1(num);
            }).start();
        }
    }
}

结果为:
在这里插入图片描述

由于代码中 synchronized (Data3.class)锁的是Data3.class这个类对象,
所以对于代码中的那5个线程,每次执行fun1(num)方法时,只有当一个线程获取到Data3.class这个类的锁之后,执行完func1(num)方法,释放了Data3.class的锁之后,才能执行下一个线程;

(2)synchronized(对象):锁的是同一个对象

class Data3{
    public   void func2(Integer num) {
        synchronized (num) {//锁的是同一个num对象
            System.out.println(num+"start....");
            try {
                TimeUnit.SECONDS.sleep(3);//休眠3秒
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("end....");
        }
    }
}

Test:

import java.util.concurrent.TimeUnit;

public class Test3 {

    public static void main(String[] args) {

        Data3 data=new Data3();
        for(int i=0;i<5;i++){
            Integer num=Integer.valueOf(1);//同一个num对象
            new Thread(()->{
                data.func2(num);
            }).start();
        }
    }
}

结果为:
在这里插入图片描述

由于代码中 synchronized (num)锁的是num这个实例对象;
又由于 Integer num=Integer.valueOf(1),不管创建多少次,都是对应的堆中的同一个对象,
所以对于代码中的那5个线程,每次执行fun2(num)方法时,锁的时同一个num,只有当一个线程获取到num这个对象的锁之后,执行完func2(num)方法,释放了num的锁之后,才能执行下一个线程;

Test3:

public class Test3 {

    public static void main(String[] args) {

        Data3 data=new Data3();
        for(int i=0;i<5;i++){
            Integer num=Integer.valueOf(i);//不同的num对象
            new Thread(()->{
              data.func2(num);
            }).start();
        }
     
    }
}

结果为:
在这里插入图片描述
由于代码中 synchronized (num)锁的是num这个实例对象;
又由于 Integer num=Integer.valueOf(i),这5次创建过程中,对应的是不同的num实例对象;

所以对于代码中的那5个线程,每次执行fun2(num)方法时,锁的都不是同一个num的锁,他们互不影响,所以5个线程同时执行;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章