Java多线程之线程安全(2)Thread介绍

#一.概况
为了连贯和帮助理解后面的同步方式还是要记录一下Thread。前面Java多线程之线程安全(0)Java内存区域与Java内存模型中已经介绍了Java中线程的本质。下面主要看一下我们的Thread中有什么方法,以及各个方法的作用。
####涉及的点

  • Thread的状态
  • Thread的方法
  • Object中和线程有关方法
    ####sdk的版本是27
    #二.Thread的状态
    Thread作为CPU的调度单位,在运行的过程中有几个状态,在不同的状态中做不同的工作,而状态间的切换是关键(也就是我们如何控制这些状态的切换,调用什么方法)。为了和下面的各个方法对应上,这里将block状态拆分为了waiting,time waiting,block三种状态,如下图:
    这里写图片描述

##2.1Thread的几个方法(和上图相关的,其他的下面介绍)
#####1.start方法(实例的方法)
start()用来启动一个线程,当调用start方法后,系统才会开启一个新的线程来执行用户定义的子任务,在这个过程中,会为相应的线程分配需要的资源。
#####2.run方法(实例的方法)
我们不用手动调用,他是一个回调方法,当本线程获得CPU的执行时间run方法运行。在这里我们执行在本线程中的操作。
#####3.join方法(实例的方法),有三个重载方法

  • join()
  • join(long millis)//参数单位为毫秒
  • join(long millis, int nanos)//第一参数单位为毫秒,第二个参数单位为纳秒

假如在main线程中,调用thread.join方法,则mainThread会等待thread线程执行完毕或者等待一定的时间。如果调用的是无参join方法,则等待thread执行完毕,如果调用的是指定了时间参数的join方法,则等待一定的时间。
#####4.sleep方法,有两个重载方法(类方法)
交出CPU,让CPU去执行其他的任务,不会释放锁,也就是说如果当前线程持有对某个对象的锁,则即使调用sleep方法,其他线程也无法访问这个对象。
调用了sleep方法,必须捕获InterruptedException异常或者将该异常向上层抛出。当线程睡眠时间满后,不一定会立即得到执行,因为此时可能CPU正在执行其他的任务。所以说调用sleep方法相当于让线程进入阻塞状态。

  • sleep(long millis)://参数单位为毫秒
  • sleep(Object lock, long millis, int nanos)://第一参数单位为毫秒,第二个参数单位为纳秒
    Thread类的方法,其实是目前正在执行的线程去睡眠。
    #####5.打断方法
  • thread.interrupt();
  • Thread.interrupted();
  • thread.isInterrupted();

首先说明一下,无论调用哪个方法都只是处理的“打断标识”,而不是真的去阻止线程的运行

下面说明各个方法。
第一个:分以下几种情况(作用于thread,也就是实例)
a.如果线程堵塞在object.wait、Thread.join和Thread.sleep,将会抛出InterruptedException,同时清除线程的中断状态;
b.如果线程堵塞在java.nio.channels.InterruptibleChannel的IO上,Channel将会被关闭,线程被置为中断状态,并抛出java.nio.channels.ClosedByInterruptException;
c.如果线程堵塞在java.nio.channels.Selector上,线程被置为中断状态,select方法会马上返回,类似调用wakeup的效果;
第二个方法:Thread类的interrupted方法(作用于currentThread,也就是正在运行的线程)
判断的是当前线程是否处于中断状态。是类的静态方法,同时会清除线程的中断状态
第三个方法:
判断的是当前线程是否处于中断状态,不会清除线程的中断状态
######总结一下:
interrupt()是用来设置中断状态的,线程被阻塞例如调用了wait,sleep,join,那么就抛出中断异常让我们处理,说明当前线程已经被中断,不需要继续保持中断位,此时内部会清除中断状态(我们此时调用isInterrupted 方法返回false);此时如果你想保持中断状态,可以再次调用interrupt方法设置中断状态。这样做的原因是,java的中断并不是真正的中断线程,而只设置标志位(中断位)来通知用户。
interrupted是静态方法,返回的是当前线程的中断状态。如果当前线程被中断(没有抛出中断异常),你调用interrupted方法,第一次会返回true。然后,当前线程的中断状态被方法内部清除,第二次调用时就会返回false。
如果你刚开始一直调用isInterrupted,则会一直返回true,因为没有清除中断状态操作,除非中间线程的中断状态被其他操作清除了。
6.yield方法
调用yield方法会让当前线程交出CPU权限,让CPU去执行其他的线程。它跟sleep方法类似,同样不会释放锁。但是yield不能控制具体的交出CPU的时间,另外,yield方法只能让拥有相同优先级的线程有获取CPU执行时间的机会。
注意,调用yield方法并不会让线程进入阻塞状态,而是让线程重回就绪状态,它只需要等待重新获取CPU执行时间,这一点是和sleep方法不一样的。
##2.2Object类中的方法(和线程同步相关的)
#####1.wait方法
Object中有三个wait的重载方法,分别是

  • wait():使正在运行的线程进入等待状态,直到其他线程调用notify或notityAll方法。
  • wait(long millis):使正在运行的线程进入等待状态,知道其他线程调用notify或notityAll方法。或者millis时间长度过后。
  • wait(long millis, int nanos):使正在运行的线程进入等待状态,知道其他线程调用notify或notityAll方法。或者millis+nanos时间长度过后。前者单位是毫秒,后者是纳秒。
    #####2.notify
  • notify:只能唤醒一个如果有好多个以这个实例为监视器,且是随机的。
  • notifyAll:唤醒所有的。

#三.Thread中其他方法
下面几个方法主要是设置Thread属性的方法。
#####1.getId
用来得到线程ID
#####2.getName和setName
用来得到或者设置线程名称。(也可以调用带名字的构造方法设置线程名字)
#####3.getPriority和setPriority
用来获取和设置线程优先级。
#####4.setDaemon和isDaemon
用来设置线程是否成为守护线程和判断线程是否是守护线程。
守护线程和用户线程的区别在于:守护线程依赖于创建它的线程,而用户线程则不依赖。举个简单的例子:如果在main线程中创建了一个守护线程,当main方法运行完毕之后,守护线程也会随着消亡。而用户线程则不会,用户线程会一直运行直到其运行完毕。在JVM中,像垃圾收集器线程就是守护线程。

参考:《Java编程思想》

猜你喜欢

转载自blog.csdn.net/gongxiaoou/article/details/81126582
今日推荐