方法 | 功能 |
start() | 启动线程并执行相应的run()方法 |
run() | 线程要执行的代码放入run()方法 |
getName() | 获取此线程的名字 |
setName() | 设置此线程的名字 |
getID() | 获取线程ID |
getPriority() | 获取线程优先级 |
setPriority() | 线程优先级和线程调度器 |
setDaemon() | 设置当前线程为守护线程。 |
currentThread() | 静态的,调取当前的线程 |
yield() | 释放自己拥有的CPU |
join() | 使得放弃当前线程的执行,并返回对应的线程。 |
interrupt() | 中断线程 |
方法详解
start() 和 run() 方法
start是启动一个线程
run被当做一个普通的方法调用
class Thread3 implements Runnable{
@Override
public void run() {
System.out.println("线程名:"+Thread.currentThread().getName());
System.out.println("线程ID:"+Thread.currentThread().getId());
System.out.println("线程优先级:"+Thread.currentThread().getPriority());
}
}
public class Demo1 {
public static void main(String[] args) {
Thread3 b = new Thread3();
Thread thread = new Thread(b);
thread.start();//启动线程
thread.run();//当做普通方法来运行
}
}
运行结果
线程名:main
线程ID:1
线程优先级:5
线程名:Thread-0
线程ID:8
线程优先级:5
上图中调用start 方法启动thread这个线程,start 调用自身run方法,所以显示为 线程名:Thread-0
调用run方法相当于在主线程中调用thread的run方法,当前线程显示为 线程名:main
setName() 和 getName()
setName():设置线程的名字
getName() :获取线程的名字
public static void main(String[] args) {
Thread3 b = new Thread3();
Thread thread1 = new Thread(b);
thread1.setName("线程1");
thread1.start();
}
运行结果:
线程名:线程1
线程ID:8
线程优先级:5
还是刚才的代码,getName()获取到的名字就是线程1 了。
setPriority() 和 getPriority()
getPriority() :获取线程的优先级
setPriority() :设置线程的优先级
public static void main(String[] args) {
Thread3 b = new Thread3();
Thread thread1 = new Thread(b);
thread1.setPriority(1);
thread1.start();
}
}
运行结果:
线程名:Thread-0
线程ID:8
线程优先级:1
线程优先级 : 优先级越高,被优先调用的概率越高。(默认为 5 )
1 - 10
在JVM 层是优先执行的,但是在操作系统层是由操作系统自己决定的。
JVM :优先级越高会优先执行。
操作系统:线程优先级越高,优先执行的概率越高。
所以说优先级高并不代表一定会执行,只是说明执行的概率比较大。
setDaemon()
设置当前线程为守护线程
守护线程:守护线程是脱离于中断的线程。
守护线程存活,当存在守护线程和用户线程时,JVM 存活
当只有守护线程时,JVM 就不在了。
通俗来讲守护线程就是在后台运行的线程,用户一般感知不到它的存在,jvm 中的GC收集器就是守护线程。
yield() 和 join()
yield():释放当前cpu
yield()是让当前正在运行的程序回到可运行状态,使得与当前线程相同优先级的线程获得运行的机会。因此,使用yield()方法的目的是让相同优先级的线程之间能适当的轮换执行。
但是,实际中当前线程释放cpu后也可能再次通过线程调度策略再次获得cpu使用权,不一定能达到目的。
class Thread2 implements Runnable{
@Override
public void run() {
for(int i = 0;i < 10;i++){
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
public class Demo3 {
public static void main(String[] args) {
Thread1 d = new Thread1();
Thread t1 = new Thread(d,"线程1");
Thread t2 = new Thread(d,"t2");
t1.start();
t2.start();
}
运行结果:
线程1: 0
t2: 0
t2: 1
t2: 2
t2: 3
t2: 4
t2: 5
线程1: 1
线程1: 2
t2: 6
线程1: 3
t2: 7
线程1: 4
t2: 8
线程1: 5
t2: 9
线程1: 6
线程1: 7
线程1: 8
线程1: 9
join():加入线程
当前执行线程是A 线程,调用join方法的是B 线程
先暂停A 线程,执行B 线程,B 线程执行完成之后再调用A 线程。
public class Demo3 {
public static void main(String[] args) {
Thread2 d = new Thread2();
Thread t1 = new Thread(d,"线程1");
t1.start();
for(int i = 0;i < 10;i++){
System.out.println(Thread.currentThread().getName()+":"+i);
if(i == 5){
try {
t1.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
运行结果:
线程1:1
main:2
main:3
线程1:2
main:4
线程1:3
main:5
线程1:4
线程1:5
线程1:6
线程1:7
线程1:8
线程1:9
main:6
main:7
main:8
main:9
从运行结果可以看出当主线程中 i = 5 时,主线程停止运行,等到线程1运行完主线程继续运行。
interrupt()
中断线程操作实质上是修改了一下中断标识位;
当前线程正在运行,仅仅修改标识位不做其他的;
当前线程正在阻塞,修改标识位,如果是join、sleep、yield,则会抛出InterruptedException,修改标识位false.
关于interrupt() 方法,可以参考这篇博客,写的非常好:Interrupt()详解