【Java基础】线程笔记——ThreadApi

来源:互联网 发布:防蓝光 软件 编辑:程序博客网 时间:2024/04/30 14:38

线程的中断机制

第一种方法: Thread.stop() (已废弃)
【缺点】线程不安全,已不再使用

第二种方法: Thread.interrupt()

当一个线程运行时,另一个线程可以调用对应的 Thread 对象的 interrupt()方法来中断它,该方法只是在目标线程中设置一个标志,表示它已经被中断,并立即返回。

如果只是单纯的调用 interrupt()方法,线程并没有实际被中断,会继续往下执行

public class InteruptThread implements Runnable {    @Override    public void run() {        boolean stop = false;        while(!stop){            System.out.println("This Thread is Running ......");            long time = System.currentTimeMillis();            while((System.currentTimeMillis() - time < 1000)){            }            //当interrupt=true时,需要去处理它的中断状态,不然线程会一直运行            if(Thread.currentThread().isInterrupted()){                Thread.currentThread().interrupt();                break;            }        }        System.out.println("This Thread Exit Under Request");    }  }

运行

public static void main(String[] args) throws InterruptedException {        Thread t = new Thread(new InteruptThread(),"Interupt");        System.out.println("InteruptThread starting ...");        t.start();        Thread.sleep(3000);        System.out.println("InteruptThread interupted");        t.interrupt();        System.out.println("线程是否中断---->"+t.isInterrupted());        Thread.sleep(3000);        System.out.println("Stop Application");}

console

InteruptThread starting ...This Thread is Running ......This Thread is Running ......This Thread is Running ......InteruptThread interupted线程是否中断---->trueThis Thread Exit Under RequestStop Application

如果去掉if语句判断去处理中断状态,线程一直会一直运行(形成死循环)

InteruptThread starting ...This Thread is Running ......This Thread is Running ......This Thread is Running ......InteruptThread interupted线程是否中断---->trueThis Thread is Running ......This Thread is Running ......This Thread is Running ......Stop ApplicationThis Thread is Running ......This Thread is Running ......

注意:一定要对Thread.isInterrupted()状态进行处理

补充(yield()和join()使用)

  • join 方法用线程对象调用,如果在一个线程 A 中调用另一个线程 B 的 join 方法,线程 A 将会等待线程 B 执行完毕后再执行。
  • yield 可以直接用 Thread 类调用,yield 让出 CPU 执行权给同等级的线程,如果没有相同级别的线程在等待 CPU 的执行权,则该线程继续执行。

守护线程(后台运行线程)

守护线程不需要关心它何时结束,进程结束,守护线程自动结束

不要在守护线程中执行业务逻辑操作(比如对数据的读写等)

必须在启动线程前标记守护线程
setDeamon(true);

Java垃圾回收、内存管理就是一个守护线程

注意

  • setDaemon(true)必须在调用线程的 start()方法之前设置,否则会跑出 IllegalThreadStateException 异常。
  • 在守护线程中产生的新线程也是守护线程。
  • 不要认为所有的应用都可以分配给守护线程来进行服务,比如读写操作或者计算逻辑

线程阻塞

  1. 当线程执行 Thread.sleep()时,它一直阻塞到指定的毫秒时间之后,或者阻塞被另一个线程打断;
  2. 当线程碰到一条 wait()语句时,它会一直阻塞到接到通知(notify())、被中断或经过了指定毫秒时间为止(若制定了超时值的话)
  3. 线程阻塞与不同 I/O 的方式有多种。常见的一种方式是 InputStream的read()方法,该方法一直阻塞到从流中读取一个字节的数据为止,它可以无限阻塞,因此不能指定超时时间;
  4. 线程也可以阻塞等待获取某个对象锁的排他性访问权限(即等待获得 synchronized 语句必须的锁时阻塞)。

线程组

方便管理线程,并且可以为某些线程设置相同特定的属性
例如:setDeamon()、设置未处理异常的处理方法、设置统一的安全策略等

每个ThreadGroup都可以包含一组子线程或者一组子线程组

在一个进程中线程组是以树形存在

system线程组是所有线程的顶级父线程组

//获取当前线程的线程组Thread.currentThread().getThreadGroup()
  • Java中允许对一个线程组中所有线程进行操作
  • Java多线程另一个重要的特性就是线程安全。线程组机制允许通过分组来区分不同特性的线程

线程池和线程组区别:线程组方便管理线程对象。线程池管理线程的声明周期,复用线程,减少创建销毁进程的开销

线程安全

当前线程副本ThreadLocal

  • ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每个线程都可以独立的改变自己的副本(Local想表达的意思)

  • remove() 是jdk5以后新增的方法,java会自动垃圾回收变量,调用该方法加快垃圾回收的速度
  • get()/set() 得到/设置ThreadLocal的值
    -initialValue() 返回变量的初始值,只执行一次。若缺省,直接返回一个null
public class ThreadLocalValue {    private static ThreadLocal<Integer> seqNum = new ThreadLocal<Integer>(){        protected Integer initialValue() {return 0;};    };    public Integer nextNum(){        seqNum.set(seqNum.get() + 1);        return seqNum.get();    }    public ThreadLocal<Integer> getThreadLocal(){        return seqNum;    }}

运行

public static void main(String[] args) {        ThreadLocalValue value = new ThreadLocalValue();        TestClient t1 = new TestClient(value);        TestClient t2 = new TestClient(value);        TestClient t3 = new TestClient(value);        t1.start();        t2.start();        t3.start();    }    static class TestClient extends Thread{        private ThreadLocalValue tlv = null;        public TestClient(ThreadLocalValue tlv){            this.tlv = tlv;        }        @Override        public void run() {            for (int i = 0; i < 3; i++) {                System.out.println("thread["+Thread.currentThread().getName()+"] ---> value : "+tlv.nextNum());            }            tlv.getThreadLocal().remove();        }}

console

thread[Thread-2] ---> value : 1thread[Thread-1] ---> value : 1thread[Thread-0] ---> value : 1thread[Thread-1] ---> value : 2thread[Thread-2] ---> value : 2thread[Thread-1] ---> value : 3thread[Thread-0] ---> value : 2thread[Thread-0] ---> value : 3thread[Thread-2] ---> value : 3

上面可得出
所产生的序号虽然共享一个实例,但是没用互相干扰,而是各自独立产生序列号,确定每个线程单独提供了一个变量副本

源码解析
set
这里写图片描述
1.首先通过getMap(t)得到当前相关ThreadLocalMap,将值放入map中,如果为空则重新创建Map createMap(t,value)

ThreadLocalMap 是线程隔离的核心,它是ThreadLocal的静态内部类,实现了键值对的设置和获取(对比Map) 存储的值,只能被当前线程读取和修改,ThreadLocal操作每个线程特有的ThreadLocalMap,从而实现了变量在不同线程中的隔离
ThreadLocalMap的键的this对象指的就是ThreadLocal,值就是所存储的值。

static class ThreadLocalMap

这里写图片描述


这里写代码片


这里写图片描述

总结

ThreadLocal处理线程的局部变量,要比synchronized同步机制解决线程问题更简单,更方便,而且结果程序拥有更高的并发性

线程的异常处理

所有异常必须在run方法进行处理,不能抛出throw exception

  • 方法一:在try…catch内处理
  • 方法二:实现一个UncaughtExceptionHandler接口

处理unchecked异常
这里写图片描述

设计一个异常线程B

public class ThreadB implements Runnable {    @Override    public void run() {        int num = Integer.parseInt("A");        System.out.println(num);        System.out.println("This is Exception Thread B ");    }}

处理线程异常

public class ExceptionOfThreadB implements UncaughtExceptionHandler {    @Override    public void uncaughtException(Thread t, Throwable e) {        System.out.println("Thread -->"+t.getName()+"("+t.getId()+")");        System.out.println("Thread Exception -->"+e.getClass().getName());        System.out.println("exception message -->"+e.getMessage());        System.out.println("state -->" + t.getState());    }}

运行

public static void main(String[] args) {        ThreadB threadException = new ThreadB();        Thread t = new Thread(threadException,"threadException");        //设置异常        t.setUncaughtExceptionHandler(new ExceptionOfThreadB());        t.start();    }

console

Thread -->threadException(10)Thread Exception -->java.lang.NumberFormatExceptionexception message -->For input string: "A"state -->RUNNABLE
0 0