多线程的方式有Thread、Runnable、Callable、ExecutorService四种方式
1.Thread、Runnable区别
(1) Thread是类,Runnable是接口(支持多继承)。Thread可以理解成实现了Runnable接口的类。
(2) Runnable资源共享实现较简单。
(3) 增加程序的健壮性,代码可以被多个线程共享,代码和数据独立
(4) 线程池只能放入实现Runable或callable类线程,不能直接放入继承Thread的类
2.Runnable、Callable区别
(1)Runnable是run() , Callable是call()。其中Runnable可以提交给Thread来包装下,Callable一般都是提交给ExecuteService和FutureTask来执行。
(2)Callable能获取返回值和抛出异常。
class c implements Callable<String>{
@Override
public String call() throws Exception {
return null;
}
}
class r implements Runnable{
@Override
public void run() {
}
}
设置当前线程的未捕获异常处理器
public void setUncaughtExceptionHandler(UncaughtExceptionHandler eh)
当未设置的时候会调用jvm默认的异常处理一下执行。
(3)Callable获取值时会导致所在的线程等待,直到get返回值为止,返回之前会中断当前线程。
future模式:并发模式的一种,可以有两种形式,即无阻塞和阻塞,分别是isDone和get。其中Future对象用来存放该线程的返回值以及状态
future.isDone() //return true,false 无阻塞
future.get() // return 返回值,阻塞直到该线程运行结束
四种实现多线程方式:https://blog.csdn.net/u011480603/article/details/75332435/
3.启动线程
start()是真真的开启一个线程执行,会分配资源。
run()只是线程的一个普通方法,调用方法会进入调用者所在线程的等待执行队列(不会在新线程执行),当前面Runnable执行完毕后再执行。
4.停止线程
(1)使用退出标志(volatile 布尔变量),也就是当run方法完成后线程终止。
(2)使用interrupt / interrupted方法阻塞线程(修改线程中断标记值) ,isInterrupted()返回线程标记值。
调用interrupt()方法,立刻改变的是中断状态,但如果不是在阻塞态,就不会抛出异常;如果在进入阻塞态后(Object.wait, Thread.join和Thread.sleep),中断状态为已中断,就会立刻抛出异常
(3)使用stop方法强行终止线程 (这个方法不推荐使用,因为stop和suspend、resume一样,也可能发生不可预料的结果)
附Join用法(同步):https://blog.csdn.net/qq_33236248/article/details/80266487
5.线程异常
线程出现异常结果
(1)线程运行 ->线程处理了异常或抛出
(2)线程停止 ->发生异常线程没有捕获或没有将其抛出,此时JVM会使用Thread.getUncaughtExceptionHandler()来查询线程的UncaughtExceptionHandler并将线程和异常作为参数传递给handler的uncaughtException()方法进行处理
使用步骤
第一步:implements UncaughtExceptionHandler 自定义异常处理类
第二步:Thread t = new Thread(new ExceptionThread());
t.setUncaughtExceptionHandler(new MyUnchecckedExceptionhandler());
t.start();
6.线程同步
synchronized方法、synchronized模块(wait/notify机制)、ReenreantLock、volatile、while轮询等方式
(1)synchronized方法
由于java的每个对象都有一个内置锁,当用此关键字修饰方法时,
内置锁会保护整个方法。在调用该方法前,需要获得内置锁,否则就处于阻塞状态
(2)synchronized模块 - wait/notify机制
同步是一种高开销的操作,因此应该尽量减少同步的内容
通常没有必要同步整个方法,使用synchronized代码块同步关键代码即可
(3) ReenreantLock
JavaSE1.5.新增了一个java.util.concurrent包来支持同步。
ReentrantLock类是可重入、互斥、实现了Lock接口的锁,
它与使用synchronized方法和快具有相同的基本行为和语义,并且扩展了其能力
ReenreantLock类的常用方法有:
ReentrantLock() : 创建一个ReentrantLock实例
lock() : 获得锁
unlock() : 释放锁 - finally 中执行
从上可看出 他在写法上相对synchronized 更简洁
(4) volatile
可见性 - 使用volatile修饰域相当于告诉虚拟机该域可能会被其他线程更新.因此每次使用该域就要重新计算,而不是使用寄存器中的值
有序性 - 编译优化时 ,将不改变此修饰过的变量执行顺序
7.如何避免死锁?
Java多线程中的死锁 死锁是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。这是一个严重的问题,因为死锁会让你的程序挂起无法完成任务,死锁的发生必须满足以下四个条件:
1、互斥条件:一个资源每次只能被一个进程使用。
2、请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
3、不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
4、循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
解决死锁
1、 加锁顺序
2、加锁时限
3、死锁检测
https://www.cnblogs.com/android-blogs/p/5765148.html
死锁代码、检测
https://www.cnblogs.com/itsoku123/p/10974157.html
8、线程状态
9.常见问题
(1)wait/notify机制
以生产者和消费者为例
调用任意方法,必须在对象锁方法体中
生产者调用notify后,生产者所在线程并不会立即退出线程,得等到生产者执行完毕。消费者才有可能机会执行
消费者被唤醒后是从wait()方法(被阻塞的地方)后面执行,而不是重新从同步块开头
(2)notify和notifyAll区别
notify()方法不能唤醒某个具体的线程,所以只有一个线程在等待的时候它才有用武之地。
notifyAll()唤醒所有线程并允许他们争夺锁确保了至少有一个线程能继续运行
(3)wait() 和 sleep()有什么不同?
sleep()方法仅仅释放CPU资源或者让当前线程停止执行一段时间,但不会释放锁
释放锁资源,进入资源等待池等待
参考:https://www.cnblogs.com/hapjin/p/5492619.html
(4)sleep 、yield区别
yield和 sleep 一样都是 Thread 类的方法,都是暂停当前正在执行的线程对象,和 sleep 不同的是 yield方法并不会让线程进入阻塞状态,而是让线程重回就绪状态,它只需要等待重新获取CPU执行时间,所以执行yield()的线程有可能在进入到可执行状态后马上又被执行。还有一点和 sleep 不同的是 yield 方法只能使同优先级或更高优先级的线程有执行的机会
Thread相关方法
public static Thread.yield() //当前线程可转让cpu控制权,让别的就绪状态线程运行(切换)
public static Thread.sleep() //暂停一段时间
public join()//在一个线程中调用other.join(),将等待other执行完后才继续本线程。
public interrupte()//后两个函数皆可以被打断
参考:https://www.cnblogs.com/wxd0108/p/5479442.html
(4)Synchronized和ReentrantLock的区别
ReentrantLock是类,那么它就提供了比synchronized更多更灵活的特性,可以被继承、可以有方法、可以有各种各样的类变量,ReentrantLock比synchronized的扩展性体现在几点上:
(1)ReentrantLock可以对获取锁的等待时间进行设置,就是给锁设定一个等待时间。如果过了等待时间线程还没有获取锁,那么线程就自动放弃获取该锁,这样就避免了死锁
(2)ReentrantLock可以获取各种锁的信息
(3)ReentrantLock可以灵活地实现多路通知
另外,二者的锁机制其实也是不一样的。ReentrantLock底层调用的是Unsafe的park方法加锁,synchronized操作的应该是对象头中mark word
参考:https://blog.csdn.net/qq_41212104/article/details/81773717