多线程学习笔记(七)之wait与sleep的区别、线程停止及守护线程等
2017-05-06 22:05
441 查看
wait()方法与sleep()方法的区别
wait()方法与sleep()方法的区别:wait可以指定时间也可以不指定时间;sleep必须指定时间
在同步中时,对cpu的执行权和锁的处理不同:
wait:释放cpu执行权,释放锁
sleep:释放cpu执行权,不释放锁
停止线程
定义循环结束标记
因为线程运行代码一般都是循环,只要控制了循环即可。例如通过flag的方式:
class StopThread implements Runnable{ private boolean flag = true; public void run(){ while (flag){ System.out.println(Thread.currentThread().getName()+"......"); } } public void setFlag(){ flag = false; } } public class StopThreadDemo { public static void main(String[] args){ StopThread st = new StopThread(); Thread t1 = new Thread(st); Thread t2 = new Thread(st); t1.start(); t2.start(); int num = 1; for (;;){ if (++num==50){ st.setFlag(); break; } System.out.println("main..."+num); } System.out.println("over"); } }
但是上述通过flag的方式有时候也不能使线程停止,例如我们修改下StopThread类的代码:
class StopThread implements Runnable{ private boolean flag = true; public synchronized void run(){ while (flag){ try{ wait(); }catch (InterruptedException e){ System.out.println(Thread.currentThread().getName()+"......"+e); } System.out.println(Thread.currentThread().getName()+"......"); } } public void setFlag(){ flag = false; } }
当线程Thread0获得执行权时,由于wait陷入等待状态,之后当Thread1获得执行权时,由于wait陷入等待状态,此时主线程执行结束,flag设置为false,但是却无法停止线程Thread0与Thread1,两者一直处于等待状态。也就是说,如果线程处于冻结状态(sleep时间很长的时候也是同理),无法读取标记,那么如何使这种情况的线程结束?下面的方式就可以解决这种问题。
使用interrupt(中断)方法
该方法是结束线程的冻结状态,使线程回到运行状态中来。(注:stop方法已经过时不再使用)
public void interrupt():中断线程
如果线程在调用Object类的wait(),wait(long)或wait(long,int)方法,或者该类的join(),join(long),join(long,int),sleep(long)或sleep(long,int)方法过程中受阻,则其中断状态将被清除(中断状态指程序冻结,即停止运行),它还将收到一个InterruptedException。即interrupt方法可以不等到sleep时间到即可以把其唤醒,是强制性的,因此是在程序应该等待的时候使其中断,会抛出InterruptedException异常。
因此对上述程序进行修改:
class StopThread implements Runnable{ private boolean flag = true; public synchronized void run(){ while (flag){ try{ wait(); }catch (InterruptedException e){ System.out.println(Thread.currentThread().getName()+"......"+e); flag = false; } System.out.println(Thread.currentThread().getName()+"......"); } } public void setFlag(){ flag = false; } } public class StopThreadDemo { public static void main(String[] args){ StopThread st = new StopThread(); Thread t1 = new Thread(st); Thread t2 = new Thread(st); t1.start(); t2.start(); int num = 1; for (;;){ if (++num==50){ t1.interrupt(); t2.interrupt(); break; } System.out.println("main..."+num); } System.out.println("over"); } }
运行结果:
t1.interrupt()与t2.interrupt()将线程从冻结状态中强制恢复到运行状态中来,让线程具备cpu的执行资格,但是会发生异常InterruptedException,因此原本处于try块中等待的线程t0与t1再interrupt方法之后抛出异常,进入catch块,通过在catch块中将flag置为false使其跳出while循环,最终达到停止线程的目的。
interrupt()只是改变中断状态而已
interrupt()不会中断一个正在运行的线程。这一方法实际上完成的是,在线程受到阻塞时抛出一个中断信号,这样线程就得以退出阻塞的状态。更确切的说,如果线程被Object.wait, Thread.join和Thread.sleep三种方法之一阻塞,那么,它将接收到一个中断异常(InterruptedException),从而提早地终结被阻塞状态。
如果线程没有被阻塞,这时调用interrupt()将不起作用;否则,线程就将得到异常(该线程必须事先预备好处理此状况),接着逃离阻塞状态。
wait() & interrupt()
线程A调用了wait()进入了等待状态,也可以用interrupt()取消.
不过这时候要小心锁定的问题.线程在进入等待区,会把锁定解除,当对等待中的线程调用interrupt()时(注意是等待的线程调用其自己的interrupt(),例如上述demo中的t1与t2调用各自的interrupt方法),会先重新获取锁定,再抛出异常.在获取锁定之前,是无法抛出异常的.
守护线程
void setDaemon(boolean on):将该线程标记为守护线程(后台线程)或者用户线程。当正在运行的线程都是守护线程时,Java虚拟机退出。该方法必须在启动线程前调用。参数:on——如果为true,则将该线程标记为守护线程。
例如仍是上面的例子的main方法修改下:
public class StopThreadDemo { public static void main(String[] args){ StopThread st = new StopThread(); Thread t1 = new Thread(st); Thread t2 = new Thread(st); t1.start(); t2.setDaemon(true); t2.start(); int num = 1; for (;;){ if (++num==50){ t1.interrupt(); //t2.interrupt(); break; } System.out.println("main..."+num); } System.out.println("over"); } }
虽然没有使用t2.interrupt(),但是由于将线程t2设置成为了守护线程,因此当最后由于等待wait只剩下t2线程时,其仍会停止,即只剩下守护线程时,其将停止,无论处于什么状态。
join方法
public final void join() throws InterruptedException :等待该线程终止,**抛出**InterruptException-如果任何线程中断了当前线程。当抛出该异常时,当前线程的中断状态被清除。(注:会抛出异常的时候,要么在所在函数的声明位置加上throws Exception,要么将其放入try{}catch{}块中)
class DemoTest implements Runnable{ public void run(){ for (int x=0;x<50;x++){ System.out.println(Thread.currentThread().getName()+"......"+x); } } } public class JoinDemo { public static void main(String[] args) throws Exception{ DemoTest d = new DemoTest(); Thread t1 = new Thread(d); Thread t2 = new Thread(d); t1.start(); //临时加入一个线程运算时可以使用join方法 t1.join();//t1线程要申请加入进来运行,主线程等待t1终止之后再执行,即此时主线程处于冻结状态,是可以使用interrupt方法强制恢复回来的 t2.start(); t2.setPriority(Thread.MAX_PRIORITY); //t1.join();//t1线程要申请加入进来运行,主线程等待t1终止之后再执行,注意此时开启的线程是t1与t2,即t1与t2互相争夺执行权,但是主线程仅仅与t1线程相关联,在线程t1执行结束后主线程开始执行 for (int x=0;x<50;x++){ System.out.println(Thread.currentThread().getName()+"......"+x); } }
优先级
优先级越高代表被cpu执行的概率越大(1到10),一般1、5与10的差距是最大的。因为是静态常量,因此需要加上类名
字段摘要:Thread.MAX_PRIORITY,线程可以具有的最高优先级;Thread.MIN_PRIORITY,线程可以具有的最低优先级;Thread.NORM_PRIORITY,分配给线程的默认优先级,例如:
t2.setPriority(Thread.MAX_PRIORITY);
Thread.yield()方法
yield():暂停当前正在执行的线程对象,并执行其他线程yield()应该做的是让当前运行线程回到可运行状态,以允许具有相同优先级的其他线程获得运行机会。
因此,使用yield()的目的是让相同优先级的线程之间能适当的轮转执行。但是,实际中无法保证yield()达到让步目的,因为让步的线程还有可能被线程调度程序再次选中。例如:
class DemoTest implements Runnable{ public void run(){ for (int x=0;x<50;x++){ System.out.println(Thread.currentThread().getName()+"......"+x); Thread.yield(); } } }
相关文章推荐
- 32-多线程(wait和sleep的区别)1 2 33-多线程(停止线程方式-定义标记) 35-多线程(守护线程-setDaemon).1 2
- 【Java基础_(线程篇_第一篇)】继承Thread;实现runnable;sleep、wait用法和区别;Thread和Runnable区别;线程停止
- Java Thread(线程)案例详解sleep和wait的区别
- java线程 sleep()和wait()的区别
- java线程的sleep(),wait(),notify(),yield()方法的区别要点
- 线程的yield(),sleep()以及wait()的区别
- java线程的sleep(),wait(),notify(),yield()方法的区别要点
- Java线程中sleep()、wait()和notify()和notifyAll()、suspend和resume()、yield()、join()、interrupt()的用法和区别
- 线程中wait与sleep的区别以及stop和interrupt的区别
- Java线程中sleep()、wait()和notify()和notifyAll()、yield()、join()等方法的用法和区别
- Java线程中sleep()、wait()和notify()和notifyAll()、yield()、join()等方法的用法和区别
- 线程中sleep和wait有什么区别
- java线程中yield(),sleep(),wait()区别详解
- java线程同步原理及wait,notify的用法及与sleep的区别
- Java线程中sleep和wait的区别
- Java线程中sleep和wait的区别
- 线程——线程间的通信——wait()的区别 和sleep()
- Java线程中sleep和wait的区别详细介绍
- java线程wait与sleep的区别
- java线程同步原理及wait,notify的用法及与sleep的区别