FS全栈计划

线程学习笔记(一)

2017-12-13  本文已影响15人  MaxZing

01 线程的创建与销毁

启动:start();

注意点:thread对象虽然可以直接调用run方法,但是,直接调用run方法不会启动新线程,只是在当前线程执行run方法而已,只有使用start方法,才会启动新线程!

自然停止的线程无须关系,因为执行结束就自动停止了。
然而对可以无限时间执行的线程,需要注意:

stop方法不能手动直接调用。
stop方法会直接将线程置空,会抛出ThreadDeath错误,无法预料线程对数据的影响。
interrupt方法对处于阻塞中的线程,无法处理
线程执行sleep或wait方法时,或是读取文件,执行interrupt会抛出异常,因为中断线程导致线程无法完成正在等待的任务。

提倡方法,run方法中使用isInterrupted()作为终止条件

   public void run() {
        while(!isInterrupted()){
            正常逻辑
        }
    }

    public synchronized void stopTheThread(){
        isInterrupted = false;
    }

这样调用interrupt方法时,逻辑会在执行完成后停止线程。

ps: interrupt不能中断正在进行的数据写入。

02 JVM中线程的内存分布工作方式

Java线程的内存模型基础知识

线程中的异常处理

所有线程都不允许抛出未捕获的checked exception,如果线程任务中有checked exception,需要自己catch住,并处理掉,如果是unchecked exception出现的话,这个线程就挂了,当然,不会直接影响其他线程,导致其他线程或宿主宕掉。
如果想处理unchecked exception,可以使用public void uncaughtException(Thread t, Throwable e) 方法处理,但是这个方法依旧在Thread内部。而且若是在线程池中,这个方法是不会被调用的。
╮(╯╰)╭

03 死锁与解决办法

什么是线程死锁,看一段代码

        String lock1 = "l1";
        String lock2 = "l2";

        Thread t1 = new Thread(()->{
            synchronized (lock1){
                System.out.println("t1:"+lock1);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                synchronized (lock2){
                    System.out.println("t1:"+lock2);
                }
            }
        });


        Thread t2 = new Thread(()->{
            synchronized (lock2){
                System.out.println("t2:"+lock1);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                synchronized (lock1){
                    System.out.println("t2:"+lock1);
                }
            }
        });


        t1.start();
        t2.start();

这段代码运行后,无法退出,因为t1进入sleep后,t2占用了lock2,然后t2 没有释放lock2 就进入了sleep,切换回t1,这时候lock2被占用,无法进一步执行,等待线程时长结束后,t1没有释放lock1 导致t2也不能进入下一步执行,这就形成了死锁。

避免死锁可以从下面几个角度去修改代码,

  1. 破坏互斥条件:不要出现一个资源只能被一个进程占用,直到该进程释放资源
  2. 取消请求和保持条件:当一个线程等不到请求的资源时,不要阻塞。
  3. 剥夺条件:尽量不要让一个变量只能被一个线程独占,
  4. 打破循环等待:当发生死锁时,所等待的进程必定会形成一个环路,尽量不要让线程相互占用对方的独立资源,从而导致循环阻塞。

这四个满足一个就可以避免死锁的发生。

转载请注明出处:https://micorochio.github.io/2017/12/10/learning-thread-note-01/

上一篇下一篇

猜你喜欢

热点阅读