关于多线程面试题

1. 关键字volatile和synchronized对比?

1)volatile是线程同步的轻量级实现,而synchronized是重量级操作。volatile只能修饰变量,而synchronized可以修饰方法,以及代码块。

2)volatile仅能保证数据可见性,不能保证原子性,而synchronized既可以保证数据的可见性,也能保证原子性。

3)volatile不会造成线程的阻塞,而synchronized可能会造成线程的阻塞。

4)volatile解决的是变量在多个线程之间的可见性,而synchronized解决的是多个线程之间访问资源的同步性。

2. Lock和synchronized对比?

1)lock是一个锁,而synchronized是一个关键字。

2)lock不会主动释放锁,需要在finally块中添加unlock()去释放锁。而synchronized会主动释放锁。

3)lock可以获取锁的信息,例如是否成功获取锁,而synchronized不能。

4)lock可以让等待的线程响应中断,而synchronized不能。

5)lock可以提高多个线程读操作的效率,而synchronized不能。

3. sleep方法和wait方法的比较

相同点:

二者都可以让线程处于冻结状态。

不同点:

1)sleep方法是Thread类中定义的方法,而wait方法是Object类中定义的方法。

2)sleep方法必须人为地为其指定时间。而wait方法既可以指定时间,也可以不指定时间。

3)sleep方法时间到,线程处于临时阻塞状态或者运行状态。wait方法如果没有被设置时间,就必须要通过notify或者notifyAll来唤醒。

4)sleep方法不一定非要定义在同步中。而wait方法必须定义在同步中。

5)当二者都定义在同步中时,线程执行到sleep,不会释放锁。而线程执行到wait,会释放锁。

4. sleep方法和yield法的比较

1.sleep()方法给其他线程运行机会时不考虑线程的优先级, yield()方法只会给相同优先级或更高优先级的线程以运行的机会;

2.线程执行sleep()方法后转入阻塞(blocked)状态,而执行yield()方法后转入就绪(ready)状态;

3.sleep()方法声明抛出InterruptedException,而yield()方法没有声明任何异常;

4.sleep()方法比yield()方法(跟操作系统相关)具有更好的可移植性。

5.多线程的实现方式

public class MyThread extends Thread {  //继承Thread类
  public void run() {  
   System.out.println("MyThread.run()");  
  }  
}  
 
MyThread myThread1 = new MyThread();  
myThread1.start();  
public class MyThread implements Runnable {  //实现Runable接口
  public void run() {  
   System.out.println("MyThread.run()");  
  }  
} 

MyThread myThread = new MyThread();  
Thread thread = new Thread(myThread);  
thread.start();  
public class SomeCallable<V> implements Callable<V> {//实现Callable接口
    @Override
    public V call() throws Exception {
        return null;
    }
}

Callable<V> oneCallable = new SomeCallable<V>();   
FutureTask<V> oneTask = new FutureTask<V>(oneCallable);   
Thread oneThread = new Thread(oneTask);   
oneThread.start();   

还有第四种方式---线程池创建

6.线程的生命周期以及状态转换

  • 就绪(Runnable):线程准备运行,不一定立马就能开始执行。
  • 运行中(Running):进程正在执行线程的代码。
  • 等待中(Waiting):线程处于阻塞的状态,等待外部的处理结束。
  • 睡眠中(Sleeping):线程被强制睡眠。
  • I/O阻塞(Blocked on I/O):等待I/O操作完成。
  • 同步阻塞(Blocked on Synchronization):等待获取锁。
  • 死亡(Dead):线程完成了执行。

如果线程是因为调用了wait()、sleep()或者join()方法而导致的阻塞,可以中断线程,并且通过抛出InterruptedException来唤醒它;如果线程遇到了IO阻塞,无能为力,因为IO是操作系统实现的,Java代码并没有办法直接接触到操作系统。

7.线程阻塞的方法

sleep() 方法、suspend() 和 resume() 方法、 yield() 方法、wait() 和 notify() 方法、join()方法

8.ThreadLocal的原理及作用

解决的是变量在不同线程之间的隔离性,也就是不同线程拥有自己的值,不同线程中的值是可以放入ThreadLocal类中进行保存的。

Public static ThreadLocal t=new ThreadLocal();

1)ThreadLocal用来解决多线程程序的并发问题

2)当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本.

9.线程池(thread pool)

线程池是指在初始化一个多线程应用程序过程中创建一个线程集合,然后在需要执行新的任务时重用这些线程而不是新建一个线程。

使用线程池的好处

1、线程池改进了一个应用程序的响应时间。由于线程池中的线程已经准备好且等待被分配任务,应用程序可以直接拿来使用而不用新建一个线程。

2、线程池节省了CLR 为每个短生存周期任务创建一个完整的线程的开销并可以在任务完成后回收资源。

3、线程池根据当前在系统中运行的进程来优化线程时间片。

4、线程池允许我们开启多个任务而不用为每个线程设置属性。

5、线程池允许我们为正在执行的任务的程序参数传递一个包含状态信息的对象引用。

6、线程池可以用来解决处理一个特定请求最大线程数量限制问题。

10.CAS

实现原理:CAS是一个原子操作,CAS机制当中使用了3个基本操作数:内存地址V,旧的预期值A,要修改的新值B。更新一个变量的时候,只有当变量的预期值A和内存地址V当中的实际值相同时,才会将内存地址V对应的值修改为B。

优点:竞争不大的时候系统开销小

缺点:

  • 循环时间长CPU开销大。(在并发量比较高的情况下,如果许多线程反复尝试更新某一个变量,却又一直更新不成功,循环往复,会给CPU带来很大的压力。)

  • ABA问题。(解决方法:加个版本号。在Compare阶段不仅要比较期望值A和地址V中的实际值,还要比较变量的版本号是否一致。)

  • 只能保证一个共享变量的原子操作,不能保证代码块的原子性。

11.锁的类型--悲观锁、乐观锁

12.偏向锁、轻量级锁、重量级锁、自旋锁的概念

重量级锁Synchronized,Synchronized是非公平锁。

原文地址:https://www.cnblogs.com/mcahkf/p/9040608.html