Synchronized 关键字

139 阅读4分钟

Synchronized修饰的方法叫做同步方法。在java中每个对象都有一把锁(lock)或者叫做监视器。这里做一些比较,看一下作用范围。

首先创建一个实体类,声明2个同步方法和2个静态同步方法。

public class SyncEntity {
    private String name;
    public SyncEntity(String name) {
        this.name = name;
    }
        /**
     * 非同步方法1
     */
    public void getFood() {
        try {
            System.out.println(name + " getFood-" + DateUtils.formatDate(new Date()));
            Thread.sleep(5000);
            System.out.println(name + " returnFood-" + DateUtils.formatDate(new Date()));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 非同步方法2
     */
    public void getMoney() {
        try {
            System.out.println(name + " getMoney-" + DateUtils.formatDate(new Date()));
            Thread.sleep(5000);
            System.out.println(name + " returnMoney-" + DateUtils.formatDate(new Date()));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 同步方法1
     */
    public synchronized void getBook() {
        try {
            System.out.println(name + " getBook-" + DateUtils.formatDate(new Date()));
            Thread.sleep(5000);
            System.out.println(name + " returnBook-" + DateUtils.formatDate(new Date()));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 同步方法2
     */
    public synchronized void getPen() {
        try {
            System.out.println(name + " getPen-" + DateUtils.formatDate(new Date()));
            Thread.sleep(5000);
            System.out.println(name + " returnPen-" + DateUtils.formatDate(new Date()));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 静态同步方法1
     */
    public synchronized static void getStaticCar(String name) {
        try {
            System.out.println(name + " getStaticCar-" + DateUtils.formatDate(new Date()));
            Thread.sleep(5000);
            System.out.println(name + " returnStaticCar-" + DateUtils.formatDate(new Date()));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 静态同步方法2
     */
    public synchronized static void getStaticBus(String name) {
        try {
            System.out.println(name + " getStaticBus-" + DateUtils.formatDate(new Date()));
            Thread.sleep(5000);
            System.out.println(name + " returnStaticBus-" + DateUtils.formatDate(new Date()));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

测试不同线程执行同步代码块

    // 创建一个对象
    SyncEntity syncEntity = new SyncEntity("TestSync");
    // 创建一个线程池,这里用固定线程数量的
    ExecutorService executorService = new ThreadPoolExecutor(2,2,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<>(), new ThreadFactoryBuilder().setNameFormat("自定义线程名称-%d").build());
    executorService.execute(() -> {
        System.out.println(Thread.currentThread().getName()+" 开始执行。。。");
        synchronized (syncEntity){
            syncEntity.getFood();
        }
    });
    executorService.execute(() -> {
        System.out.println(Thread.currentThread().getName()+" 开始执行。。。");
        synchronized (syncEntity){
            syncEntity.getMoney();
        }
    });
    // 关闭线程池
    executorService.shutdown();

执行结果

自定义线程名称-0 开始执行。。。
自定义线程名称-1 开始执行。。。
TestSync getFood-Thu, 17 Oct 2019 10:09:37 GMT
TestSync returnFood-Thu, 17 Oct 2019 10:09:42 GMT
TestSync getMoney-Thu, 17 Oct 2019 10:09:42 GMT
TestSync returnMoney-Thu, 17 Oct 2019 10:09:47 GMT

结论:同步代码块锁定传入对象

测试不同线程执行同一对象上的同一方法

    // 创建一个对象
    SyncEntity syncEntity = new SyncEntity("TestSync1");
    // 创建一个线程池,这里用固定线程数量的
    ExecutorService executorService = new ThreadPoolExecutor(2,2,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<>(), new ThreadFactoryBuilder().setNameFormat("自定义线程名称-%d").build());
    executorService.execute(() -> {
        System.out.println(Thread.currentThread().getName()+" 开始执行。。。");
        syncEntity.getBook();
    });
    executorService.execute(() -> {
        System.out.println(Thread.currentThread().getName()+" 开始执行。。。");
        syncEntity.getBook();
    });
    // 关闭线程池
    executorService.shutdown();

执行结果

自定义线程名称-0 开始执行。。。
自定义线程名称-1 开始执行。。。
TestSync getBook-Thu, 17 Oct 2019 09:11:28 GMT
TestSync returnBook-Thu, 17 Oct 2019 09:11:33 GMT
TestSync getBook-Thu, 17 Oct 2019 09:11:33 GMT
TestSync returnBook-Thu, 17 Oct 2019 09:11:38 GMT

测试不同线程执行同一对象上的不同方法

    // 创建一个对象
    SyncEntity syncEntity = new SyncEntity("TestSync1");
    // 创建一个线程池,这里用固定线程数量的
    ExecutorService executorService = new ThreadPoolExecutor(2,2,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<>(), new ThreadFactoryBuilder().setNameFormat("自定义线程名称-%d").build());
    executorService.execute(() -> {
        System.out.println(Thread.currentThread().getName()+" 开始执行。。。");
        syncEntity.getBook();
    });
    executorService.execute(() -> {
        System.out.println(Thread.currentThread().getName()+" 开始执行。。。");
        syncEntity.getBook();
    });
    // 关闭线程池
    executorService.shutdown();

执行结果

自定义线程名称-0 开始执行。。。
自定义线程名称-1 开始执行。。。
TestSync getBook-Thu, 17 Oct 2019 09:38:43 GMT
TestSync returnBook-Thu, 17 Oct 2019 09:38:48 GMT
TestSync getPen-Thu, 17 Oct 2019 09:38:48 GMT
TestSync returnPen-Thu, 17 Oct 2019 09:38:53 GMT

测试不同线程执行不同对象上的同一方法

    // 创建一个对象
    SyncEntity syncEntity1 = new SyncEntity("TestSync1");
    SyncEntity syncEntity2 = new SyncEntity("TestSync2");
    // 创建一个线程池,这里用固定线程数量的
    ExecutorService executorService = new ThreadPoolExecutor(2,2,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<>(), new ThreadFactoryBuilder().setNameFormat("自定义线程名称-%d").build());
    executorService.execute(() -> {
        System.out.println(Thread.currentThread().getName()+" 开始执行。。。");
        syncEntity1.getBook();
    });
    executorService.execute(() -> {
        System.out.println(Thread.currentThread().getName()+" 开始执行。。。");
        syncEntity2.getBook();
    });
    // 关闭线程池
    executorService.shutdown();

执行结果

自定义线程名称-1 开始执行。。。
自定义线程名称-0 开始执行。。。
TestSync1 getBook-Thu, 17 Oct 2019 09:43:41 GMT
TestSync2 getBook-Thu, 17 Oct 2019 09:43:41 GMT
TestSync2 returnBook-Thu, 17 Oct 2019 09:43:46 GMT
TestSync1 returnBook-Thu, 17 Oct 2019 09:43:46 GMT

结论:同步方法锁定当前对象

测试不同线程执行不同对象上的同一方法

    // 创建一个线程池,这里用固定线程数量的
    ExecutorService executorService = new ThreadPoolExecutor(2,2,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<>(), new ThreadFactoryBuilder().setNameFormat("自定义线程名称-%d").build());
    executorService.execute(() -> {
        System.out.println(Thread.currentThread().getName()+" 开始执行。。。");
        SyncEntity.getStaticCar("小汽车");
    });
    executorService.execute(() -> {
        System.out.println(Thread.currentThread().getName()+" 开始执行。。。");
        SyncEntity.getStaticBus("公交车");
    });
    // 关闭线程池
    executorService.shutdown();

执行结果

自定义线程名称-0 开始执行。。。
自定义线程名称-1 开始执行。。。
公交车 getStaticBus-Thu, 17 Oct 2019 09:49:53 GMT
公交车 returnStaticBus-Thu, 17 Oct 2019 09:49:58 GMT
小汽车 getStaticCar-Thu, 17 Oct 2019 09:49:58 GMT
小汽车 returnStaticCar-Thu, 17 Oct 2019 09:50:03 GMT

结论:静态同步方法锁定当前类