synchronized同步代码块锁住的数据类型

422 阅读3分钟
synchronized同步代码块可以锁定任意数据,运行时类,实例对象,成员变量都可以,我们来看不同的数据类型对应的代码。


(1)运行时类

运行时类在内存中只有一份,即线程同步。

package com.southwind.thread;

public class SynchronizedTest {
        public static void main(String[] args) {
            MyRunnable myRunnable = new MyRunnable();
            for (int i = 1; i <= 5; i++) {
              new Thread(myRunnable,"线程"+i).start();
            }
          }
        }

class MyRunnable implements Runnable{
          private int num = 0;
          @Override
          public void run() {
            // TODO Auto-generated method stub
            synchronized (MyRunnable.class) {
                          num++;
              try {
                Thread.currentThread().sleep(100);
              } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
                      }
              System.out.println(Thread.currentThread().getName()+"是第"+num+"位访客");
        }
      }
    }


运行结果如图。


(2)实例对象

实例对象的创建写在for循环以外,则内存中只有一份实例对象,线程同步。

package com.southwind.thread;

public class SynchronizedTest {
    public static void main(String[] args) {
        MyRunnable myRunnable = new MyRunnable();
        for (int i = 1; i <= 5; i++) {
            new Thread(myRunnable,"线程"+i).start();
        }
    }
}

class MyRunnable implements Runnable{
    private int num = 0;
    @Override
    public void run() {
        // TODO Auto-generated method stub
        synchronized (this) {
            num++;
            try {
                Thread.currentThread().sleep(100);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"是第"+num+"位访客");
        }
    }

}

运行结果如图。


实例对象的创建写在for循环内部,则内存中有多份实例对象,线程异步。

package com.southwind.thread;

public class SynchronizedTest {
    public static void main(String[] args) {
        for (int i = 1; i <= 5; i++) {
            MyRunnable myRunnable = new MyRunnable();
            new Thread(myRunnable,"线程"+i).start();
        }
    }
}

class MyRunnable implements Runnable{
    private int num = 0;
    @Override
    public void run() {
        // TODO Auto-generated method stub
        synchronized (this) {
            num++;
            try {
                Thread.currentThread().sleep(100);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"是第"+num+"位访客");
        }
    }

}

运行结果如图。


(2.1)实例对象


(3)成员变量

内存中成员变量的个数是一个还是多个,是通过调用equals()方法来判断的,如果equals()方法返回true,表示两个变量相等,内存中只有一份,如果equals()方法返回false,表示两个变量不相等,内存中有多份。

package com.southwind.thread;

public class SynchronizedTest {
    public static void main(String[] args) {
        Object obj = new Object();
        MyRunnable myRunnable = new MyRunnable(obj);
        Object o1 = myRunnable.obj;
        for (int i = 1; i <= 5; i++) {
            myRunnable.obj = new Object();
            System.out.println(myRunnable.obj.equals(o1));
            o1 = myRunnable.obj;
            new Thread(myRunnable,"线程"+i).start();
        }
    }
}

class MyRunnable implements Runnable{
    private int num = 0;
    public Object obj;
    public MyRunnable(Object obj) {
        // TODO Auto-generated constructor stub
        this.obj = obj;
    }
    @Override
    public void run() {
        // TODO Auto-generated method stub
        synchronized (obj) {
            num++;
            try {
                Thread.currentThread().sleep(100);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"是第"+num+"位访客");
        }
    }

}

上述代码中每次循环创建线程对象时,都会重新给MyRunnable的成员变量obj赋值,所以成员变量是多个,equals方法返回false,线程异步。

运行结果如图。

略。。。

修改代码,去掉myRunnable.obj = new Object();

package com.southwind.thread;

public class SynchronizedTest {
    public static void main(String[] args) {
        Object obj = new Object();
        MyRunnable myRunnable = new MyRunnable(obj);
        Object o1 = myRunnable.obj;
        for (int i = 1; i <= 5; i++) {
            System.out.println(myRunnable.obj.equals(o1));
            o1 = myRunnable.obj;
            new Thread(myRunnable,"线程"+i).start();
        }
    }
}

class MyRunnable implements Runnable{
    private int num = 0;
    public Object obj;
    public MyRunnable(Object obj) {
        // TODO Auto-generated constructor stub
        this.obj = obj;
    }
    @Override
    public void run() {
        // TODO Auto-generated method stub
        synchronized (obj) {
            num++;
            try {
                Thread.currentThread().sleep(100);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"是第"+num+"位访客");
        }
    }

}

每次循环创建线程对象时,没有重新给MyRunnable的成员变量obj赋值,所以成员变量是一个,equals方法返回true,线程同步。

运行结果如图。


参考来源:https://cloud.tencent.com/developer/article/1355674


下面参考:https://www.bilibili.com/video/av45946533/?p=31

(4)静态方法 锁的是这个类的所有对象实例调用者 

package com.mmall.practice.example.sync;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@Slf4j
public class SynchronizedExample2 {

    // 修饰一个静态的方法
    // 其作用的范围是整个静态方法,作用的对象是这个类的所有对象
    public static synchronized void test1() {

        for (int i = 0; i < 10; i++) {
            log.info("test1 - {}", i);
        }
    }

    // 修饰一个类,
    // 其作用的范围是synchronized后面括号括起来的部分,作用主的对象是这个类的所有对象。
    public static void test2() {

        synchronized (SynchronizedExample2.class) {

            for (int i = 0; i < 10; i++) {
                log.info("test2 - {}", i);
            }
        }
    }

    public static void main(String[] args) {
        SynchronizedExample2 example1 = new SynchronizedExample2();
        SynchronizedExample2 example2 = new SynchronizedExample2();
        ExecutorService exec = Executors.newCachedThreadPool();
       // public static synchronized void test1() 其作用的范围是整个静态方法,加锁的对象是这个类的所有对象example1,example2
        // example1.test1();和 example2.test1();是同步執行的只有其中一个执行完,另一个才会执行
        exec.execute(() -> {
            try {
                example1.test1();
            } catch (Exception e) {
                log.error("exception1", e);
            }
        });
        exec.execute(() -> {
            try {
                example2.test1();
            } catch (Exception e) {
                log.error("exception2", e);
            }
        });

        // synchronized (SynchronizedExample2.class) 其作用的范围是整个静态方法,加锁的对象是这个类的所有对象example1,example2
        exec.execute(() -> {
            try {
                example1.test2();
            } catch (Exception e) {
                log.error("exception1", e);
            }
        });
        exec.execute(() -> {
            try {
                example2.test2();
            } catch (Exception e) {
                log.error("exception2", e);
            }
        });
        exec.shutdown();
    }
}