java方法内部新建线程_线程之创建和内部方法调用区别

Thread的创建

Android中有两种方式可以创建一个Thread,可以直接new 一个Thread对象,或者实现一个Runnable对象给Thread来创建Thread对象。

class Thread implements Runnable

Thread thread= new Thread(){

@Override

public void run(){

System.out.println("-------------1");

}

};

thread.start();

Thread thread1 = new Thread(new Runnable() {

@Override

public void run(){

System.out.println("-------------2");

}

});

thread1.start();

复制代码

Thread本身实现了Runnable接口,当调用Thread的run方法时,会判断是否设置了单独的Runnable对象,若设置了则执行Runnable的run方法,如果没有设置我们需要重写Thread的run方法。

Thread的中断

Thread中提供了以下三个方法来中断和判断中断Thread:

public void interrupt(){} //中断线程

public boolean isInterrupted(){} //判断线程是否被中断

public static boolean interrupted(){} //判断线程是否被中断并清除中断状态

复制代码

若当前线程处于阻塞状态或者试图执行一个阻塞操作时,调用Thread对象的interrupt方法来中断线程会导致InterruptedException异常,同时中断状态将会被复位(由中断状态变为非中断状态)。

public class SyncTask implements Runnable{

static int count = 0;

static SyncTask syncTask = new SyncTask();

@Override

public void run(){

synchronized (this){

for(int i = 0;i < 5;i++){

count++;

try {

Thread.sleep(1000);

} catch (InterruptedException e) {

e.printStackTrace();

System.out.println("interrupt="+Thread.currentThread().isInterrupted());

}

}

}

}

//执行函数

Thread thread1=new Thread(syncTask,"thread1");

thread1.start();

try {

Thread.sleep(2000);

} catch (InterruptedException e) {

e.printStackTrace();

}

thread1.interrupt();

}

//执行结果

java.lang.InterruptedException: sleep interrupted

at java.lang.Thread.sleep(Native Method)

interrupt=false

复制代码

可以看到当线程调用Thread.sleep时,线程进入阻塞状态,此时调用interrupt方法会抛出异常。如果线程处于运行状态,我们可以发现就算调用interrupt方法依然不会中断线程.

@Override

public void run(){

synchronized (this){

while (true){

System.out.println("itr="+Thread.currentThread().isInterrupted());

}

}

}

//执行函数

Thread thread1=new Thread(syncTask,"thread1");

thread1.start();

try {

Thread.sleep(2000);

} catch (InterruptedException e) {

e.printStackTrace();

}

thread1.interrupt();

}

//执行结果

。。。

itr=false

itr=true

itr=true

itr=true

itr=true

。。。

复制代码

发现指示中断的标志改变了,而线程并没有中断。所以需要我们在线程中判断是否中断了线程,来主动跳出循环结束线程。

@Override

public void run(){

synchronized (this){

while (true){

if(Thread.currentThread().isInterrupted()) return;

System.out.println("itr="+Thread.currentThread().isInterrupted());

}

}

}

复制代码

这里根据isInterrupted来判断是否中断线程,结束循环。看到这里我们可以得出如何结束线程的两种方法:

当线程处于阻塞状态或试图执行一个阻塞操作时,调用interrupt方法会抛出interrupt异常并将中断复位,此时我们可以拦截异常执行结束线程操作。

当线程处于运行状态时,需要调用interrupt方法,并在线程的run方法中判断线程中断状态来结束线程。

join方法

join() // join(0);

join(long millis, int nanos)

join(long millis)

复制代码

调用join方法的线程对象所在的线程会进入WAITING状态,等待线程对象run方法执行完毕,或者millis时间到达后才会继续往下执行。

例如以下代码:main线程会等到20s之后才会执行。

public static void main(String[] args) {

TestThread testThread = new TestThread();

testThread.start();

try {

testThread.join(20000);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println("main thread is run ");

System.out.println("---------------------");

}

static class TestThread extends Thread {

@Override

public void run() {

System.out.println("child thread is run ");

long time = System.currentTimeMillis()+20000;

while (System.currentTimeMillis()

}

System.out.println("child thread is end ");

}

}

复制代码

如果我们把join方法中millis改为2000,表明child线程执行2s后,会唤醒main线程,main线程继续执行。

join方法内部采用wait和notifyAll来实现线程的等待和唤醒。

public final void join(long millis) throws InterruptedException {

synchronized(lock) {

long base = System.currentTimeMillis();

long now = 0;

if (millis < 0) {

throw new IllegalArgumentException("timeout value is negative");

}

if (millis == 0) {

while (isAlive()) {

lock.wait(0);

}

} else {

while (isAlive()) {

long delay = millis - now;

if (delay <= 0) {

break;

}

lock.wait(delay);

now = System.currentTimeMillis() - base;

}

}

}

}

复制代码

main线程调用child线程的join方法,获得child线程的对象锁,当调用wait方法后,main线程释放对象锁,进入WAITING状态等待唤醒,不在往下执行。这里的isAlive方法判断当前子线程是否存活,若子线程不存活则main线程不在等待。

到这里我们需要考虑一下,main线程进入阻塞状态后,是如何被唤醒的?

结果就是:

唤醒操作由Thread对象的系统操作来完成,当线程执行结束后,在thread.cpp中会调用notifyAll方法唤醒所有等待的线程。

wait、notify、notifyAll使用

wait、notify、notifyAll必须在synchronized修饰的方法或者代码块中使用,否则会抛出IllegalMonitorStateException异常。因为在使用这三类方法时Thread必须获取当前对象锁的monitor监控器对象。注意wait之后,其他线程必须调用notify才会继续执行当前线程,同一时候只有一个线程可以持有monitor监控器对象,未持有monitor监控器对象的Thread调用notifyAll时。会抛出IllegalMonitorStateException异常。

Exception in thread "Thread-0" java.lang.IllegalMonitorStateException

at java.lang.Object.notifyAll(Native Method)

at com.mdy.string_struct.MyThread$TestThread.run(MyThread.java:29)

复制代码

wait 和sleep区别

sleep属于Thread的静态方法,当Thread被中断时,调用sleep方法会抛出InterruptedException异常。wait属于Obkect对象的方法,必须在synchronized修饰的方法或者代码块中使用。

wait会使当前线程暂停进入阻塞状态,并释放监控器monitor对象。sleep只会阻塞当前线程并不会释放monitor对象。调用notify、notifyAll后,也不是立即释放monitor对象,而是在synchronized方法结束后才自动释放锁。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值