三道java新手入门面试题,通往自由的道路–锁+Volatile

三道Java新手入门面试题攻略

一、什么是锁?

锁是一种同步机制,用于控制多个线程对共享资源的访问。当多个线程试图访问同一共享资源时,可能会导致数据不一致或者其他问题,而锁就可以保证同一时刻只有一个线程访问该共享资源,避免多线程并发访问发生问题。

Java提供了两种锁机制:synchronized关键字和Lock接口。

synchronized关键字

  1. synchronized方法

如果一个方法被synchronized关键字修饰,那么该方法称为同步方法。同一个对象的不同线程在调用该方法时,只能有一条线程能执行,其他线程需要等待该线程执行完毕后再进行调用。

示例代码:

public class SyncDemo implements Runnable{
    private int count = 0;

    public synchronized void increase() {
        count++;
    }

    public void run() {
        for (int i = 0;i < 10000;i++) {
            increase();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        SyncDemo syncDemo = new SyncDemo();
        Thread thread1 = new Thread(syncDemo);
        Thread thread2 = new Thread(syncDemo);
        thread1.start();
        thread2.start();
        thread1.join();
        thread2.join();
        System.out.println("Count: " + syncDemo.count);
    }
}
  1. synchronized块

除了同步方法外,synchronized关键字还可以放在代码块中,利用锁的机制保证多个线程对于共享资源的互斥访问。

示例代码:

public class SyncDemo implements Runnable{
    private static int count = 0;
    private Object lock = new Object();

    public void increase() {
        synchronized (lock) {
            count++;
        }
    }

    public void run() {
        for (int i = 0;i < 10000;i++) {
            increase();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        SyncDemo syncDemo = new SyncDemo();
        Thread thread1 = new Thread(syncDemo);
        Thread thread2 = new Thread(syncDemo);
        thread1.start();
        thread2.start();
        thread1.join();
        thread2.join();
        System.out.println("Count: " + count);
    }
}

Lock接口

Lock接口提供了比synchronized更细粒度的锁机制,它允许多个线程同时访问共享资源,但同一时刻只能有一个线程修改资源。它还提供了比synchronized更灵活的同步方式,例如可以选择公平锁或非公平锁,甚至是可以在条件变量上等待或唤醒线程。

ReentrantLock是Lock接口的一个具体实现,使用方式与synchronized类似。

示例代码:

public class LockDemo implements Runnable{
    private static int count = 0;
    private Lock lock = new ReentrantLock();

    public void increase() {
        lock.lock();
        try {
            count++;
        } finally {
            lock.unlock();
        }
    }

    public void run() {
        for (int i = 0;i < 10000;i++) {
            increase();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        LockDemo lockDemo = new LockDemo();
        Thread thread1 = new Thread(lockDemo);
        Thread thread2 = new Thread(lockDemo);
        thread1.start();
        thread2.start();
        thread1.join();
        thread2.join();
        System.out.println("Count: " + count);
    }
}

二、什么是Volatile?

Volatile是Java中的另一种同步机制,它保证对该变量的读写操作都是原子性的,即不允许出现多线程并发访问时的数据不一致问题。和synchronized关键字不同的是,Volatile是采用的可见性的思想,即对变量的更改会马上被其他线程所感知。

示例代码:

public class VolatileDemo implements Runnable {
    private volatile boolean flag = true;

    public void stop() {
        flag = false;
    }

    public void run() {
        while (flag) {
            System.out.println(Thread.currentThread().getName() + " is running...");
        }
        System.out.println(Thread.currentThread().getName() + " is stopped.");
    }

    public static void main(String[] args) throws InterruptedException {
        VolatileDemo demo = new VolatileDemo();
        Thread thread = new Thread(demo);
        thread.start();
        Thread.sleep(1000);
        demo.stop();
    }
}

三、锁和Volatile的区别

锁和Volatile都可以用来保证线程安全,但是它们的实现机制不同:

  • 锁是采用了互斥访问的方式限制对共享资源的访问,而Volatile是通过保证可见性来避免数据不一致的问题。
  • 锁可以确保资源的唯一控制权,但是需要等待获取锁的线程释放锁之后其他线程才能继续执行,因此通常会对系统性能和响应时间产生影响;而Volatile则不存在这个问题,对系统性能的开销很小。
  • 锁适用于一些复杂的互斥访问场景,例如多线程交互时,为了避免死锁或者其他等待导致的问题;而Volatile适用于对性能要求更高的单个变量访问场景,例如flag变量。

示例代码:

共享变量a,要求a的值在所有线程之间同步,运用synchronzed和Volatile的线程池示例如下:

public class SyncAndVolatileDemo {

    private int a = 0;

    public synchronized void syncIncrease() {
        a++;
    }

    private volatile int b = 0;

    public void volatileIncrease() {
        b++;
    }

    public static void main(String[] args) throws Exception {

        SyncAndVolatileDemo demo = new SyncAndVolatileDemo();

        // 线程池
        ExecutorService executorService = Executors.newFixedThreadPool(2);

        // 同步方法访问示例
        executorService.submit(() -> {
            for (int i = 0; i < 10000; i++) {
                demo.syncIncrease();
            }
        });

        // Volatile变量访问示例
        executorService.submit(() -> {
            for (int i = 0; i < 10000; i++) {
                demo.volatileIncrease();
            }
        });

        executorService.shutdown();
        executorService.awaitTermination(1, TimeUnit.MINUTES);

        System.out.println("a's value: " + demo.a);
        System.out.println("b's value: " + demo.b);
    }
} 

在同步访问a和Volatile访问b的线程池任务中,经过多次测试可以看出,同步访问的a最后的结果正常,而Volatile访问的b有时会发生丢失/重复值的情况。这表明了锁机制比Volatile更加可靠,在多线程环境中可以更好地保证数据的完整性和一致性。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:三道java新手入门面试题,通往自由的道路–锁+Volatile - Python技术站

(0)
上一篇 2023年5月19日
下一篇 2023年5月19日

相关文章

  • 在Java代码中解析html,获取其中的值方法

    要在Java代码中解析html,获取其中的值,可以使用Jsoup这个第三方开源库。下面是使用Jsoup的步骤: 第一步:导入Jsoup库 使用Maven导入依赖: <dependency> <groupId>org.jsoup</groupId> <artifactId>jsoup</artifactId…

    Java 2023年5月26日
    00
  • JavaBean实体类处理外键过程解析

    下面是针对“JavaBean实体类处理外键过程解析”的完整攻略: 1. 概述 在数据库设计中,为了避免数据冗余和提高数据存储效率,通常会使用外键来保证关系完整性。然而,在Java程序中处理外键时,我们通常需要将外键转换成JavaBean实体类中的关联对象。这个过程需要我们对JavaBean实体类进行一定的处理,下面将详细介绍这个过程。 2. 外键的处理方式 …

    Java 2023年5月26日
    00
  • java正则实现各种日期格式化

    下面详细讲解“Java正则实现各种日期格式化”的完整攻略。 什么是日期格式化? 日期格式化是指将日期转换为特定的字符串格式。在Java编程中,我们经常需要使用日期格式化来将日期按照我们的要求进行显示。 Java日期格式化 在Java中,日期格式化可以使用SimpleDateFormat类。SimpleDateFormat类可以支持许多不同的日期格式,比如年月…

    Java 2023年5月20日
    00
  • java环境中的JDK、JVM、JRE详细介绍

    JDK、JVM、JRE介绍 在学习Java编程语言时,经常会听到JDK、JVM、JRE这几个概念。那么,这些概念的具体含义是什么呢? JDK(Java Development Kit):Java开发工具包。JDK是Java开发的核心组件,包含了Java编译器、Java运行环境、Java类库等一系列组件。 JRE(Java Runtime Environmen…

    Java 2023年5月24日
    00
  • 下载远程maven仓库的jar 手动放到本地仓库详细操作

    下面是下载远程maven仓库的jar并手动放到本地仓库的完整攻略。 前提条件 必须具备maven环境,安装教程可参考官方文档:Apache Maven 官方文档 已知需要下载的远程maven仓库地址 下载远程jar包并手动放到本地仓库 打开终端或命令行工具 使用以下命令下载远程maven仓库的jar mvn dependency:get -Dartifact…

    Java 2023年5月20日
    00
  • 基于java中集合的概念(详解)

    基于java中集合的概念(详解) 在Java中,集合是一组对象的容器。它们被设计为用于操作一组对象,而不是一个单独的对象。Java中的集合框架提供了一组接口和类,用于存储和操作对象的集合。在本文中,我们将详细讲解Java中集合概念的完整攻略。 集合框架 Java集合框架包括集合、列表、映射、队列和栈等不同的接口和类。这些接口和类提供了存储和操作集合的方法。 …

    Java 2023年5月26日
    00
  • Java实现lucene搜索功能的方法(推荐)

    当我们需要为网站添加搜索功能的时候,可以使用开源搜索引擎库Lucene。Lucene是一个高效的全文搜索引擎库,他可以为你的网站提供可靠的搜索服务。虽然Lucene本身是Java编写的,但它也有很好的跨语言支持能力。现在,我们就来详细讲解“Java实现lucene搜索功能的方法”。 准备工作 下载Lucene的jar包并引入到项目中。 创建一个lucene …

    Java 2023年6月15日
    00
  • springmvc模式的上传和下载实现解析

    下面我来详细讲解一下“springmvc模式的上传和下载实现解析”的完整攻略。 一、SpringMVC框架概述 SpringMVC是基于Java的前端MVC框架,它是Spring框架的一部分,主要用于Web应用程序的开发。SpringMVC分析请求并根据请求选择适当的控制器(Controller),最终生成响应结果。 二、SpringMVC模式的文件上传实现…

    Java 2023年6月15日
    00
合作推广
合作推广
分享本页
返回顶部