实现一个线程有哪几种方式,各有什么优缺点,比较常用的是哪种?
-
考察目标
1.创建线程的四种方式
2.每一种方式的利弊
3.Lock接口比synchronized的优势是什么?
-
题目分析
1.继承Thread类
Thread类本质上是实现了Runable接口的一个实例,代表一个线程的实例。启动线程的唯一方法就是通过Thread类和start()实例方法。start()方法是一个naive方法,它将启动一个新线程,并执行run()方法。这种方式实现多线程很简单,通过自己创建的类直接extend Thread,并复写run()方法,就可以启动新线程并执行自己定义的run()方法
优点:代码简单
缺点:该类无法继承别的类
2.实现Ruabble接口
Java中的类属于单继承,如果自己的类已经extends了另一个类,就无法直接extends Thread,但是一个类继承一个类同时,是可以实现多个接口的。
优点:继承其他类。统一实现该接口的实例可以共享资源
缺点:代码复杂
3.实现Callable接口
实现Runnable和实现Callable接口的方式基本相同,不过Callable接口中的call()方法有返回值,Runnable接口中的run()方法无返回值。
4.线程池方式
线程池,其实就是一个容纳多个线程的容器,其中的线程可以重复使用,省去了频繁创建线程对象的操作,因为反复制创建线程是非常消耗资源的。
优点:自动自动化装配,易于管理,循环利用资源
5.Lock接口比synchronized块的优势是什么?
1.能够显示地获取和释放锁,锁的运用更加灵活
Lock()方法:加锁
unlock()方法:释放锁
2.可以方便地实现公平锁
公平锁:表示线程获取锁地顺序是按照线程加锁的顺序来分配的,即先来先得先进先出顺序。
非公平锁:一种获取锁的抢占机制,是随机拿到锁的,和公平锁不一样的是先进的不一定先拿到锁,这个方式可能造成某些线程一致拿不到锁,结果就是不公平的。
举例:
你需要要实现一个高效的缓存,它允许给多个用户读,但只允许一个用户写,以此来保持它的完整性,你会怎么实现它?
整体上说 Lock是synchronized的扩展版,Lock提供了无条件的、可轮询的(tryLock方法)、定时的(tryLock带参方法)、可中断的(lockInterruptibly)、可多条件队列的(newCondition方法)锁操作。另外Lock的实现类基本都支持非公平锁(默认)和公平锁,synchronized只支持非公平锁,当然,在大部分情况下,非公平锁是可提高效率的。
应用场景:
为什么要学习多线程
吞吐量:举例:你做WEB,容器帮你做了多线程,但是他只能帮你做请求层面的。简单的说,可能就是一个请求一个线程。或多个请求一个线程。如果是单线程,那同时只能处理一个用户的请求。
伸缩性:也就是说,你可以通过增加CPU核数来提升性能。如果是单线程,那程序执行到死也就利用了单核,肯定没办法通过增加CPU核数来提升性能,如果是线程,就可以提高COU的使用性能。
举例:卖票案例:一个线程相当于一个窗口,多线程相当于多个窗口卖票,多个线程就可以大大提高效率。