多线程与并发—面试题2

1、CountDownLatch和CyclicBarrier的区别?

       1)CountDownLatch作用允许一个线程等待其他线程执行完成后,才执行。而另外一个允许N个线程相互等待到某个公共屏障点,然后这组线程再同时执行。

       2)CountDownLatch计数器的值无法被重置,这个初始值只能被设置一次,不能重用,而第二个的计数器可以重用。

2、Semaphore可以控制某个资源可被同时访问的个数,通过构造函数设定一定数量的许可,通过acquire()获取

3、阻塞队列种类

        1)ArrayBlockingQueue是一个由数组支持的有界缓存的阻塞队列,在读写操作上都需要锁住整个容器,因此吞吐量与一般的实现相似,是线程安全的,生产者和消费者公用一把锁。

         2)LinkedBlockingueue是一种基于链表的阻塞队列,内部维持着一个数据缓冲队列,只有当队列缓冲区达到最大值缓存容量时,才会阻塞生产者线程,生产者端和消费者端采用独立的锁来控制数据同步

          3)上面二者区别是:a、队列大小初始化方法不同,ArrayBlockingQuenue必须指定队列大小。LinkedBlockingQueue                                           有一个默认大小。

                                          b、队列锁实现不同。

                                         c、在生产或消费时操作不同 (前者基于数组,直接将对象插入或删除,后者基于链表,需要转为                                                Node<E>进行删除或插入,生成一个额外的Node对象)

         4)PriorityBlockingQueue

               为基于数组的无界阻塞队列,会按照优先级对元素进行排序,按照优先级顺序出队。每次出队元素都是优先级最高               的。但是队内元素不是按照优先级排列。

         5)DelayQueue(缓存系统设计,缓存中对象超过有效时间,使用其查询,表示缓存时间已到)

                是一个无界阻塞队列,用于放置实现了Delayed接口的1对象,只有在延迟期才能从中提取元素。优先队列的比较基准           值是时间。

         6)SynchronousQueue

                 同步队列是一个不存储元素的队列,缓存值为1的阻塞队列。

4、如果不用锁机制如何实现共享数据访问。

       无锁化编程的方法:CPU同步原语CAS,如:无锁栈、无锁队列;Atomic包;AtomicInteger是一个支持原子操作的Integer类。

        CAS优缺点:保证了原子性,不会锁住当前线程;

                           ABA问题:CAS在操作值得时候,如果值没有变化情况下才会更新,但是如果A,变为B,又变为A,那么CAS                      进行检查时,会认为没有变化。

                           CAS需要取出内存中某个时刻的数据,在下一时刻取出后的数据与原始数据比较替换,在这个时间差内导致数                       据变化。

                           循环时间长开销大。

                           只能保证一个共享变量的原子操作。

5、java中实现多线程的四种方式?

       1)继承Thread类创建线程类(重写run方法)

       2)通过Runnable接口创建线程类。(重写run方法,创建Runnable实现类的实例,调用start启动)

       3)通过Callable和Future创建线程

       4)通过线程池创建线程(线程可复用,利用Executors创建线程池)

6、java中Runnable和Callable有什么不同?

      1)Callable定义方法为call(),Runnable中为run()

      2)Callable的call方法有返回值,run没有返回值

      3)call方法可以抛出异常,run方法不能抛出异常

7、实现线程同步

       1)synchronized的用法(同步代码块)

                这个方法中的内容不能被多个线程访问。

            修饰非静态方法

          用synchronized修饰非静态方法,会将对象上锁。

             修饰静态方法

            会对这个方法所在类的Class对象上锁。

       2)Lock用法(必须在try-catch-finally块中进行)

           将释放锁的操作放在finally块中进行,以保证锁一定被释放,防止死锁的发生。

    Lock和synchronized的区别:1、Lock是一个接口,而synchronized是java关键字,是内置语言实现。

                                               2、synchronized在发生异常时会自动释放线程占有的锁,因此不对发生死锁,而Lock发生异                                                       常时,需要释放锁操作。

                                               3、Lock可以让等待锁的响应中断。

                                               4、Lock有一个方法可以判断是否获取锁(tryLock()方法)

8、volatile和synchronized区别

       1)volatile是变量修饰符,而synchronized作用于代码块或方法。

       2)volatile不会对变量加锁,而synchronized会对变量加锁。

       3)volatile仅能实现变量修改可见性,不能保证原子行,而synchronized可以保证变量修改可见性和原子性

       4)volatile标记的变量不会被编译器优化,禁止指令重排序。

9、悲观锁和乐观锁

      悲观锁:认为肯定有其他线程来争夺资源,因此不管到底会不会发生争夺,都会锁住资源,会导致其它所有需要锁的线程挂起。

      乐观锁:每次不加锁,如果因为冲突失败就重试,直到成功为止。通常基于CAS原子指令来实现。

10、实现线程间的通信?

     1)Object类中wait()\notify()\notifyAll()方法

     2)用Condition接口

     3)管道实现通信(管道只能在两个线程之间传递数据,只能实现单向发送)

     4)使用volatile关键字

11、如何确保线程安全?

    Synchronized、Lock、原子类、同步容器、并发容器、阻塞队列、同步辅助类(CountDownLatch,Semaphore,CyclicBarrier)

12、多线程优点和缺点?

       1、充分利用cpu,避免cpu空转

       2、程序响应快。

       3、上下文切换的开销大

       4、增加了资源消耗

       5、编程更加复杂

13、多线程锁的种类

   代码层次:同步锁、可重入锁、公平锁、读写锁

  数据库层次:悲观锁、乐观锁、表锁、行锁、页锁

 可重入锁(ReentrantLock和synchronized):如果当前线程已经获得某个监视器对象所持有的锁,那么该线程再该方法中调用另外一个同步方法也持有该锁。

  可中断锁(可以中断的锁,Lock为可中断锁)

  公平锁(synchronized为非公平锁,无法保证等待线程获取锁的顺序,而ReentrantLock和ReentrantReadWriteLock默认为非公平锁,但是可以设置为公平锁,尽量按请求锁的顺序获取锁)

14、锁优化

    1、自旋锁

      为了让线程等待,让线程执行一个忙循环。

    2、锁清除

     虚拟机即时编译编译器在运行时,对一些代码上要求同步,但检测到不可能存在共享数据竞争锁进行清除。

    3、锁粗化

       如果虚拟机探测到有一串零碎的操作都对同一对象加锁,将会把加锁同步范围扩大到整个操作序列外部。

    4、轻量级锁

      在代码进入同步快时,如果此同步对象没有被锁定,虚拟机将首先在当前线程中简历一个名为锁记录的空间,用于存储锁对象目前的Mark Word拷贝。

    5、偏向锁。

       目的在于消除无竞争情况下同步源于,进一步提高程序运行性能。

15、wait()和sleep()区别

       1)来自不同类,sleep来自Thread类,是静态方法。wait()是Object类,实现线程通信。

       2)sleep是将当前线程挂起指定的时间,没有释放锁。wait释放了锁。

       3)wait只能在同步控制方法和同步控制块中。

16、java中interrupted和isInterrupted区别

     前者为静态方法,后者为非静态方法,interrupted作用域当前正运行的线程,isInterrupted作用域调用该方法的线程对象所对应的线程。

    前者会中断状态清除而后者不会。

17、java中start()和run()区别?

     start()方法来启动线程,并在新线程中运行run()方法,真正实现多线程运行。

    直接调用run()方法的话,会把run()当做普通方法调用,会在当前线程执行run()方法,而不会启动新线程运行

18、线程上下文切换?

      对于单核CPU,只能在一个时刻运行一个线程,当在运行一个线程的时候去运行另一个线程叫上下文切换。

19、用户线程和守护线程

     在用户线程调用start方法之前,调用对象的setDamon(true)方法,一个守护线程是在后台执行且不会阻止JVM终止的线程,作为为为其它线程运行提供便利服务,当没有用户线程在运行时,JVM关闭程序且退出。

20、什么是线程调度器

      是一个操作系统服务,负责为Runnable状态的线程分配CPU时间。

21、线程状态

     创建、就绪、运行、阻塞、死亡

22、有三个线程,如何确保他们按顺序执行

      join方法(Thread类中的join方法的主要作用就是同步,它可以使得线程之间的并行执行变为串行执行

23、主线程中,要求大量子线程执行完,在执行主线程。

    1)join方法

        t1.start()

       t2.start()

       t3.start()

        t1.join()

        t2.join()

        t3.join()

     2)CountDownLatch,一个同步辅助类,在完成一组正在其它线程中执行操作之前,允许一个或多个线程等待

     3)使用线程池

24、ThreadLocal原理

         相当于一个容器,用于存放每个线程的局部变量。实例通常来说都是private static类型,一般情况下,通过ThreadLocal.set到线程中的对象是该线程自己使用的对象,其它线程是访问不到的,各个线程中访问的是不同的对象,如果进去的东西本来是共享的对象,那么get到的依旧是共享对象本身。

          向ThreadLocal中set的变量是由Thread线程对象自身保存的,当用户调用时,该方法则是通过currentThread获取当前线程,将变量存入线程ThreadLocalMap类中,Map中元素的键为当前threadlocal对象,而值对应线程中变量副本。

25、如何在两个线程中共享数据

     一、每个线程执行代码相同

           可以共同使用同一个Runnable对象。

     二、代码不同

           将共享数据封装为一个对象,将对象传递给不同代码的Runnable对象。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值