run与start方法
线程的run()方法是由java虚拟机直接调用的,如果我们没有启动线程(没有调用线程的start()方法)而是在应用代码中直接调用run()方法,那么这个线程的run()方法其实运行在当前线程(即run()方法的调用方所在的线程)之中,而不是运行在其自身的线程中,从而违背了创建线程的初衷
public class MyThread extends Thread{
public void run(){
//获取当前正在执行的线程对象的名称
System.out.println(Thread.currentThread().getName());
}
}
public class Test{
public static void main(String[] args){
MyThread thread = new MyThread(); //创建线程
thread.run();//直接调用run方法
System.out.println(Thread.currentThread().getName());
thread.start();//调用start方法,通过jvm调用run方法
}
}
//控制台输出如下
main //执行main方法 主线程调用构造方法
main //主线程直接调用run方法 并没有开启新线程
Thread-0 //主线程调用start方法,开启新线程,再通过jvm执行run方法
join与sleep方法
void sleep(long millis):Thread类静态方法,线程进入阻塞状态,在指定时间(单位为毫秒)到达之后进入就绪状态(Runnable),而非立即进入执行状态。
join方法:执行该方法的线程进入阻塞状态,直到调用该方法的线程结束后再由阻塞转为就绪状态。下面举个栗子
class MyThread extends Thread{
public void run(){
for(int i = 0; i<5; i++){
System.out.println("我的线程:"+i);
try{
Thread.sleep(1000);
}catch(InterruptedException e){
e.printStackTrace();
}
}
}
}
class YourThread extends Thread{
private MyThread myThread;
public YourThread(MyThread myThread) {
this.myThread = myThread;
}
public void run(){
for(int i = 0; i<3; i++){
if(i==2){
try{
myThread.join();
}catch(InterruptedException e){
e.printStackTrace();
}
}
System.out.println("你的线程:"+i);
}
}
}
public class Test{
public static void main(String[] args){
MyThread myThread = new MyThread();
myThread.start();
YourThread yourThread = new YourThread(myThread);
yourThread.start();
}
}
控制台输出如下:
第一个红框是两个线程抢占CPU使用权的结果,当MyThread线程循环一次后会通过sleep方法进入阻塞状态一秒之后才能进入第二次循环
但是我们会发现第二个红框中,我的线程已经将所有的循环完成了,最后你的线程才执行
这里的原因是因为:在两个线程抢占式运行的过程中,YourThread在循环中i=2了,这时myThread对象调用了join方法,
我们通过定义可以知道,执行该方法的线程进入了阻塞状态,直到调用该方法的线程结束后再由阻塞转为就绪状态。
我们的YourThread线程执行了该方法,而MyThread线程对象调用了该方法。
interrupt方法
interrupt方法:结束线程在调用Object类的wait方法或该类的join方法、sleep方法过程中的阻塞状态。
class MyThread extends Thread{
public void run(){
System.out.println("before time:"+ new Date());
try {
Thread.sleep(30000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("after time:"+ new Date());
}
}
public class Test{
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
myThread.interrupt();
}
}
运行结果如图:我们可以发现,本来两个时间之间的间隔应该有30秒那么久,现在却只有1秒
currentThread方法
currentThread方法:返回当前正在执行的线程对象。
具体运用情况 参考run与start方法。
isAlive方法
isAlive方法:判定该线程是否处于就绪、运行或阻塞状态,如果是则返回true,否则返回false。
class PrintThread extends Thread{
private Thread thread;
public PrintThread(Thread thread) {
this.thread = thread;
}
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.err.println(thread.isAlive());
}
}
public class Test{
public static void main(String[] args) {
Thread thread = Thread.currentThread();
new PrintThread(thread).start();
System.out.println(thread.isAlive());
}
}
控制台输出结果如下:我们可以发现,起初我们的主线程还没有死亡,当执行完main方法最后一行代码时,PrintThread线程中的run方法还在进行,可此时主线程的任务执行完毕已经死亡,所以第二个输出为false
setDaemon方法
setDaemon方法:用于将一个尚未调用 线程start方法 的线程设置为守护线程。守护线程主要用于为其他线程的运行提供服务(Java中的垃圾回收机制就是守护线程),这种线程属于创建它的线程。
注意:守护线程随着最后一个非守护线程的终止而终止。
public class Test{
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.setDaemon(true);
myThread.start();
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class MyThread extends Thread{
@Override
public void run() {
while(true) {
System.out.println("111");
}
}
}
控制台输出如下:控制台只输出了一毫秒,然后进程就终止了
原因是因为,主线程是最后一个非守护线程,主线程在1毫秒后终止,则所有的守护线程都终止了,包括我们的MyThread
yield方法
void yield():静态方法,当前线程放弃占用CPU资源,回到就绪状态,使其他优先级不低于此线程的线程有机会被执行。
setPriority方法
void setPriority(int newPriority):设置当前线程的优先级,线程优先级越高,线程获得执行的次数越多,Java线程的优先级用整数表示,取值范围是1~10,Thread类有以下三个静态常量:
- static int MAX_PRIORITY 最高优先级值为10
- static int NORM_PRIORITY 默认优先级值为5
- static int MIN_PRIORITY 最低优先级值为1
注意:同一个线程类创建的多个线程,线程优先级越高的线程获得的执行次数极有可能越多;但是不同线程类创建的线程,线程优先级越高,执行次数不一定越多,这个run方法的代码复杂度有关。
int getPriority():获得当前线程的优先级。