创建线程
本质行就两种 extends Thread 和 implement Runnable
展开了说有: 内部类 、lambda、Timer(定时器)、Callable 、线程池、FutureTask
//匿名内部类
new Thread(){
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}.start();
//匿名内部类
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}).start();
// 实现Runnable接口
public class RunnableStyle implements Runnable{
public static void main(String[] args) {
Thread thread = new Thread(new RunnableStyle());
thread.start();
}
@Override
public void run() {
System.out.println("用Runnable方法实现线程");
}
}
// lambda表达式创建线程
new Thread(() -> System.out.println(Thread.currentThread().getName())).start();
// 线程池创建线程
ExecutorService executorService = Executors.newCachedThreadPool();
for (int i = 0; i < 1000; i++) {
executorService.submit(new Task() {
});
}
停止线程
interrupt方法仅仅只是将该状态置为true。对于非阻塞中的线程, 只是改变了中断状态, 即Thread.isInterrupted()将返回true,并不会使程序立即停止;它只是要求线程自己在合适的时机中断自己
1.如果一个线程在内部被中断,Object.wait()或者Thread.join()抛出一个线程InterruptedException,这会重置线程的中断状态
2.如果那个线程在执行一个低级可中断阻塞方法,例如Thread.sleep(), Thread.join()或 Object.wait(),那么它将取消阻塞并抛出InterruptedException。(2)否则,interrupt() 只是设置线程的中断状态。在被中断线程中运行的代码以后可以轮询中断状态,看看它是否被请求停止正在做的事情。中断状态可以通过 Thread.isInterrupted()来读取,并且可以通过一个名为Thread.interrupted() 的操作读取和清除
interrupt 中断线程分为两种:
[1] 普通情况 线程正在执行时收到 Interrupted ,线程根据情况中断线程
[2] 线程在阻塞状态下 ①收到 Interrupted ②判断是中断状态 ,抛出InterruptedException异常 阻塞状态先会
[3] while中的异常会抛出,但不能停止线程 《while内的try/catch问题》
注: **sleep 会清除 interrupt的标记位 **
try/catch 在while内 并且有sleep时 interrupt的标记位 会被sleep 清除
while 在 try/catch内 并且有sleep时 interrupt的标记位 不会被清除
[4] run无法抛出checked Exception,只能用try/catch
注: ①优先选择 传递中断 (对应[5])②不想或无法传递时: 恢复中断[对应[6]]
[5] catch了InterruptedExcetion之后的优先选择:在方法签名中抛出异常 那么在run()就会强制try/catch
public class RightWayStopThreadInProd implements Runnable {
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
System.out.println("go");
try {
throwInMethod();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
//保存日志、停止程序
System.out.println("保存日志");
e.printStackTrace();
}
}
}
//抛出中断异常 InterruptedException
private void throwInMethod() throws InterruptedException {
Thread.sleep(2000);
}
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new RightWayStopThreadInProd());
thread.start();
Thread.sleep(1000);
thread.interrupt();
}
}
[6] 在catch子语句中调用Thread.currentThread().interrupt()来恢复设置中断状态,以便于在后续的执行中,依然能够检查到刚才发生了中断
回到刚才RightWayStopThreadInProd补上中断,让它跳出
public class RightWayStopThreadInProd2 implements Runnable {
@Override
public void run() {
while (true) {
if (Thread.currentThread().isInterrupted()) {
System.out.println("Interrupted,程序运行结束");
break;
}
reInterrupt();
}
}
private void reInterrupt() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
//重新设置中断
Thread.currentThread().interrupt();
e.printStackTrace();
}
}
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new RightWayStopThreadInProd2());
thread.start();
Thread.sleep(1000);
thread.interrupt();
}
}
[7] 响应中断的方法总结列表
Object.wait()/wait(long)/wait(long,int)
Thread.sleep()
Thread.join()
java.util.concurrent.BlockingQueue.take()/put(E)
java.util.concurrent.locks.Lock.lockInterruptibly()
java.util.concurrent.CountDownLatch.await()
java.util.concurrent.CyclicBarrier.await()
java.util.concurrent.Exchanger.exchane(V)
java.nio.channels.InterruptibleChannel 相关方法
java.nio.channels.Selector的先关方法
[8] isInterrupted 和interrupted方法
interrupted (重置执行interrupted方法的线程的中断状态(interrupted 状态))
isInterrupted 返回对用对象的中断状态(interrupted 状态)
线程生命周期
wait notify notifyAll
- sleep: 使当前线程(即调用该方法的线程)暂停执行一段时间,让其他线程有机会继续执行,但它并不释放对象锁。
- join :方法使调用该方法的线程在此之前执行完毕,也就是等待该方法的线程执行完毕后再往下继续执行。
- yield :(暂停当前正在执行的线程对象,并执行其他线程(–其他线程包括当前线程–)) 该方法与sleep()类似,只是不能由用户指定暂停多长时间,并且yield()方法只能让同优先级的线程有执行的机会
public class Wait {
public static Object object = new Object();
static class Thread1 extends Thread {
@Override
public void run() {
synchronized (object) {
System.out.println(Thread.currentThread().getName() + "开始执行了");
try {
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程" + Thread.currentThread().getName() + "获取到了锁。");
}
}
}
static class Thread2 extends Thread {
@Override
public void run() {
synchronized (object) {
object.notify();
System.out.println("线程" + Thread.currentThread().getName() + "调用了notify()");
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread1 thread1 = new Thread1();
Thread2 thread2 = new Thread2();
thread1.start();
Thread.sleep(200);
thread2.start();
}
}
synchronized (object) 获取object对象的锁
object.wait(); 释放object的锁,当前线程进入等待状态
object.notify(); 唤醒线程 释放锁(同步代码块执行完毕后释放锁)
wait notify notifyAll 相对底层 类似功能可以使用Condition类来完成
sleep方法不释放锁(synchronized 和 lock锁 )
** sleep不释放lock(lock需要手动释放)**
public class SleepDontReleaseLock implements Runnable {
private static final Lock lock = new ReentrantLock();
@Override
public void run() {
//获取锁
lock.lock();
System.out.println("线程" + Thread.currentThread().getName() + "获取到了锁");
try {
Thread.sleep(5000);
System.out.println("线程" + Thread.currentThread().getName() + "已经苏醒");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
//释放锁
lock.unlock();
}
}
public static void main(String[] args) {
SleepDontReleaseLock sleepDontReleaseLock = new SleepDontReleaseLock();
//第一个线程通过lock.lock();获取到锁 ,sleep不释放锁 只有执行完才释放锁 ,所以第一个线程执行完后 第二个线程才能执行(因为 第二个线程获取不到锁)
new Thread(sleepDontReleaseLock).start();
new Thread(sleepDontReleaseLock).start();
}
}
线程sleep 和wait 的区别
1、这两个方法来自不同的类分别是Thread和Object
2、最主要是sleep方法没有释放锁,而wait方法释放了锁,使得其他线程可以使用同步控制块或者方法。
3、wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在任何地方使用(使用范围)
4、sleep必须捕获异常,而wait,notify和notifyAll不需要捕获异常
join
join()方法的作用,是等待这个线程结束; ,t.join()方法阻塞调用此方法的线程(calling thread)进入 TIMED_WAITING 状态,直到线程t完成,此线程再继续;
推荐使用工具类 CountDownLatch 或 CyclicBarrier 替代join方法
守护线程 和 普通线程
整体无区别
唯一区别在于JVM的离开
时候是守护线程:
① 继承父线程
② setDaemon
未捕获异常的处理
线程的未捕获异常UncaughtExceptionHandle
为什么需要UncaughtExceptionHandle?
① 主线程可以捕获异常 子线程无法捕获异常
② 子线程异常无法通过传统方式捕获
③ 不能直接捕获的后果 提高健壮性
解决方案:
1、(不推荐)手动在每个run方法里进行try catch
2、(推荐)利用UncaughtExceptionHandle
public class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
private String name;
public MyUncaughtExceptionHandler(String name) {
this.name = name;
}
@Override
public void uncaughtException(Thread t, Throwable e) {
Logger logger = Logger.getAnonymousLogger();
logger.log(Level.WARNING, "线程异常,终止啦" + t.getName());
System.out.println(name + "捕获了异常" + t.getName() + "异常");
}
}
死锁 线程饿死 活锁
参考:
https://www.cnblogs.com/onlywujun/p/3565082.html