多线程(3)线程中的常用结构
1、构造器
- public Thread() :分配一个新的线程对象。
- public Thread(String name) :分配一个指定名字的新的线程对象。
- public Thread(Runnable target) :指定创建线程的目标对象,它实现了Runnable接口中的run方法
- public Thread(Runnable target,String name) :分配一个带有指定目标新的线程对象并指定名字。
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("a try");
}//传入匿名对象并重写run方法
},"Thread Three").start();
关于Runnable target 的传参:(1)可以传入匿名对象,例如new Runnable()
(2)可以传入 一个实现了Runnable接口的(重写了run方法)实现类的实例对象
2、介绍方法
start():启动线程,调用线程的run()
run():将线程中需要执行的操作写入,无论是继承Thread类还是实现Runnable接口都需要重写
currentThread():获取当前执行代码对应的线程
getName():获取线程名
setName():设置线程名
sleep(long millis):静态方法,调用时可以使当前线程睡眠制定的秒数,使用时必须捕获异常,可能因为被打断而抛出的异常名为:InterruptedException。
yield():静态方法,一旦执行就释放释放CPU的执行权(可能执行另一线程)
join():在线程A中通过线程B调用join(),意味着线程A进入阻塞状态,直到线程B执行完毕,线程A才恢复运行。
isAlive():线程是否存活,返回值类型true 或者 false
public class EvenNumber {
public static void main(String[] args) {
Print p = new Print("Thread one");//给线程命名
p.setName("Thread Two");
p.start();
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("a try");
}
},"Thread Three").start();//此处使用包含Runnable target参数和String name参数的构造器。
try {
Print.sleep(3);//静态方法,通过子类调用
//Thread.sleep(3);也可以直接通过Thread父类调用。
}catch (Exception e){
e.getMessage();
}//此处调用try-catch处理编译时异常,不能采用throws的原因是Print继承于Tread父类,父类中没有写throws方法子类中也不能使用。
Print.yield();//静态方法,原理同上。
for (int i = 0; i <=100; i++) {
if(i%2==0)
System.out.println(Thread.currentThread().getName()+":"+i);
if (i==20){
try {
p.join();//满足if条件时,main线程阻塞,直到Thread Two结束线程
}catch (Exception e){
e.getMessage();
}
}
while (i==90){
System.out.println(p.isAlive());
break;
}
}
}
}
class Print extends Thread{
public Print() {
}
public Print(String name) {
super(name);
}
public Print(Runnable target, String name) {
super(target, name);
}
@Override
public void run() {
for (int i = 0; i <=100; i++) {
if(i%2==0)
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
过时的方法:
stop():强行结束线程的执行
void suspend():暂停线程
void resume():恢复线程,二者必须成对使用,否则可能造成死锁,不建议使用
线程的优先级:
getPriority():获取线程的优先级(默认5)
setPriority();设置线程的优先级(1-10)
优先级高 的线程被CPU分配执行的概率大一些,这一点在单核CPU中更为明显。
MAX_PRIORITY(10):最高优先级
MIN_PRIORITY(1):最低优先级
NORM_PRIORITY(5):普通优先级
3、线程的生命周期
最初的(JDK1.5)的分类:出生、就绪、运行、死亡、阻塞
JDK1.5之后:
6种状态:NEW RUNNABLE BLOCKED WAITING TIME_WAITING TERMINATED
三种阻塞的具体分类:
锁阻塞(BLOCK):等待一个监视器锁<-- -Lock synchronlzed
获得监视器锁对象之后回到Runnable状态。
计时等待(TIME_WATING):Thread类的sleep或join,Object类的wait,LockSupport类的park方法,并且在调用这些方法时,设置了时间
具体方法介绍;Tread sleep、带有超时值的Object的wait、带有超时值的Tread 的jion、lockSupport.parkNanos、LockSupport.parkUntil
直到时间到或interrup打断等待才重新回到Runnable之中。
-
无限等待(WAITING):一个正在无限期等待另一个线程执行一个特别的(唤醒)动作的线程
具体方法以及对应的解决方案:
-
-
-
- 通过Object类的wait进入WAITING状态的要有Object的notify/notifyAll唤醒;
- 通过Condition的await进入WAITING状态的要有Condition的signal方法唤醒;
- 通过LockSupport类的park方法进入WAITING状态的要有LockSupport类的unpark方法唤醒
- 通过Thread类的join进入WAITING状态,只有调用join方法的线程对象结束才能让当前线程恢复;
-
-
说明:当从WAITING或TIMED_WAITING恢复到Runnable状态时,如果发现当前线程没有得到监视器锁,那么会立刻转入BLOCKED状态。
课件内容补充:
守护线程的特点:在后台运行,作用是为其他线程提供服务。如果所有的非守护线程都死亡,那么守护线程自动死亡。
JVM的垃圾回收线程就是典型的守护线程。
调用setDaemon(true)方法可将指定线程设置为守护线程。必须在线程启动之前(调用start方法之前)设置,否则会报IllegalThreadStateException异常。
public class ProtectTest {
public static void main(String[] args) {
Protector p = new Protector();
p.setDaemon(true);//在start之前设置守护线程
p.start();
for(int i =0;i<10;i++){
System.out.println(i);
}
}
}
class Protector extends Thread{
@Override
public void run() {
while (true){
System.out.println("I'm protecting you.");
try {
Thread.sleep(1);
}catch (Exception e){
e.getMessage();
}
}
}
}