java 多线程整理

创建线程

本质行就两种 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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值