面试题首页 > 多线程面试题

线程安全面试题

001线程安全的概念?

多个线程可以共享进程的堆和方法区资源,既多个线程共享类变量。多个线程共享一个进程的变量时,如果线程对这个变量只有读操作,没有更新操作则这个线程没有线程安全问题。如果线程需要对这个变量进行修改操作,则可能会因为数据更新不及时导致变量信息不准确而引发线程不安全。

002线程安全如何保证?

当多个线程对同一个资源进行操作的时候就会有线程安全。解决线程安全的核心思想就是加锁。加锁有两种方式:1.JVM提供的锁,就是synchronized锁,即同步代码和同步代码块 2.jdk提供的各种锁,如lock。

003Java中哪些集合是线程安全的?

在JDK1.1版本中,所有的集合都是线程安全的。但是在1.2及以后的版本中就出现了一些线程不安全的集合,为什么版本升级反而会出现一些线程不安全的集合呢?因为线程不安全的集合普遍比线程安全的集合效率高的多。随着业务的发展,特别是在WEB应用中,为了提高用户体验,减少用户的等待时间,页面的响应速度(也就是效率)是优先考虑的。而且对线程不安全的集合加锁以后也能达到安全的效果(但是效率会低,因为会有锁的获取以及等待)。其实在JDK源码中相同效果的集合线程安全的比线程不安全的就多了一个同步机制,但是效率上却低了不止一点点,因为效率低,所以已经不太建议使用了。下面列举一些常用的线程安全的集合。
Vector:就比ArrayList多了个同步化机制。
HashTable:就比HashMap多了个线程安全。
ConcurrentHashMap:是一种高效但是线程安全的集合。
Stack:栈,线程安全,继承与Vector。

004synchronized 关键字用法?

1)修饰实例方法: 作用于当前对象实例加锁,进入同步代码前要获得 当前对象实例的锁

synchronized void method() {
  //业务代码
}

2)修饰静态方法: 也就是给当前类加锁,会作用于类的所有对象实例 ,进入同步代码前要获得 当前 class 的锁。因为静态成员不属于任何一个实例对象,是类成员( static 表明这是该类的一个静态资源,不管 new 了多少个对象,只有一份)。所以,如果一个线程 A 调用一个实例对象的非静态 synchronized 方法,而线程 B 需要调用这个实例对象所属类的静态 synchronized 方法,是允许的,不会发生互斥现象,因为访问静态 synchronized 方法占用的锁是当前类的锁,而访问非静态 synchronized 方法占用的锁是当前实例对象锁。

synchronized void staic method() {
  //业务代码
}

3)修饰代码块 :指定加锁对象,对给定对象/类加锁。synchronized(this|object) 表示进入同步代码库前要获得给定对象的锁。synchronized(类.class) 表示进入同步代码前要获得 当前 class 的锁

synchronized(this) {
  //业务代码
}

总结:synchronized 关键字加到 static 静态方法和 synchronized(class) 代码块上都是是给 Class 类上锁。
synchronized 关键字加到实例方法上是给对象实例上锁。
尽量不要使用 synchronized(String a) 因为 JVM 中,字符串常量池具有缓存功能!

005构造方法可以使用 synchronized 关键字修饰么?

构造方法不能使用 synchronized 关键字修饰。构造方法本身就属于线程安全的,不存在同步的构造方法一说。

006synchronized使用:双重校验锁实现对象单例(线程安全)。

public class Singleton {
    private static Singleton uniqueInstance;
	// 私有化构造方法
    private Singleton() {
    }
	// 提供getInstance方法
    public  static Singleton getInstance() {
       //先判断对象是否已经实例过,没有实例化过才进入加锁代码
        if (uniqueInstance == null) {
            //类对象加锁
            synchronized (Singleton.class) {
                if (uniqueInstance == null) {
                    uniqueInstance = new Singleton();
                }
            }
        }
        return uniqueInstance;
    }
}

007同步和异步的区别?

同步:功能调用时,在没有得到结果之前,该调用就不返回或继续执行后续操作。这时程序是阻塞的,只有接收到返回的值或消息后才往下执行其他的命令。因此,简单来说,同步就是必须一件一件做事,等前一件事做完了才能做完下一件事。
异步:与同步相对,当一个异步过程调用发出后,调用者在没有得到结果之前,就可以继续执行后续操作,当这个调用完成后,一般通过状态或者回调来通知调用者。

008同步方法和同步块,哪个是更好的选择?

同步块,这意味着同步块之外的代码是异步执行的,这比同步整个方法更提升代 码的效率。请知道一条原则:同步的范围越小越好。

009为什么 wait(), notify()和 notifyAll()必须在同步方法或者同步块中被调用?

当一个线程需要调用对象的wait()方法的时候,这个线程必须拥有该对象的锁,接着它就会释放这个对象锁并进入等待状态直到其他线程调用这个对象上的notify()方法。同样的,当一个线程需要调用对象的notify()方法时,它会释放这个对象的锁,以便其他在等待的线程就可以得到这个对象锁。由于所有的这些方法都需要线程持有对象的锁,这样就只能通过同步来实现,所以他们只能在同步方法或者同步块中被调用。

010什么是线程同步和线程互斥?

同步就是协同步调,按预定的先后次序进行运行。如:你说完,我再说。这里的同步千万不要理解成那个同时进行,应是指协同、协助、互相配合。线程同步是指多线程通过特定的设置(如互斥量,事件对象,临界区)来控制线程之间的执行顺序(即所谓的同步)也可以说是在线程之间通过同步建立起执行顺序的关系,如果没有同步,那线程之间是各自运行各自的!
线程互斥是指对于共享的进程系统资源,在各单个线程访问时的排它性。当有若干个线程都要使用某一共享资源时,任何时刻最多只允许一个线程去使用,其它要使用该资源的线程必须等待,直到占用资源者释放该资源。线程互斥可以看成是一种特殊的线程同步(下文统称为同步)。

目录

返回顶部