sleep方法处理异常:InterruptedException.
当一个线程调用sleep方法处于睡眠阻塞的过程中,该线程的interrupt()方法被调用时,sleep方法会抛出该异常从而打断睡眠阻塞.
package thread;
/**
* sleep方法要求必须处理中断异常:InterruptedException
* 当一个线程调用sleep方法处于睡眠阻塞的过程中,它的interrupt()方法被调用时
* 会中断该阻塞,此时sleep方法会抛出该异常。
*/
public class SleepDemo2 {
public static void main(String[] args) {
Thread lin = new Thread(){
public void run(){
System.out.println("林:刚美完容,睡一会吧~");
try {
Thread.sleep(9999999);
} catch (InterruptedException e) {
System.out.println("林:干嘛呢!干嘛呢!干嘛呢!都破了像了!");
}
System.out.println("林:醒了");
}
};
Thread huang = new Thread(){
public void run(){
System.out.println("黄:大锤80!小锤40!开始砸墙!");
for(int i=0;i<5;i++){
System.out.println("黄:80!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
System.out.println("咣当!");
System.out.println("黄:大哥,搞定!");
lin.interrupt();//中断lin的睡眠阻塞
}
};
lin.start();
huang.start();
}
}
守护线程也称为:后台线程
- 守护线程是通过普通线程调用setDaemon(boolean on)方法设置而来的,因此创建上与普通线程无异.
- 守护线程的结束时机上有一点与普通线程不同,即:进程的结束.
- 进程结束:当一个进程中的所有普通线程都结束时,进程就会结束,此时会杀掉所有正在运行的守护线程.
package thread;
/**
* 守护线程
* 守护线程是通过普通线程调用setDaemon(true)设置而转变的。因此守护线程创建上
* 与普通线程无异。
* 但是结束时机上有一点不同:进程结束。
* 当一个java进程中的所有普通线程都结束时,该进程就会结束,此时会强制杀死所有正在
* 运行的守护线程。
*/
public class DaemonThreadDemo {
public static void main(String[] args) {
Thread rose = new Thread(){
public void run(){
for(int i=0;i<5;i++){
System.out.println("rose:let me go!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
System.out.println("rose:啊啊啊啊啊啊AAAAAAAaaaaa....");
System.out.println("噗通");
}
};
Thread jack = new Thread(){
public void run(){
while(true){
System.out.println("jack:you jump!i jump!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
}
};
rose.start();
jack.setDaemon(true);//设置守护线程必须在线程启动前进行
jack.start();
}
}
通常当我们不关心某个线程的任务什么时候停下来,它可以一直运行,但是程序主要的工作都结束时它应当跟着结束时,这样的任务就适合放在守护线程上执行.比如GC就是在守护线程上运行的.
线程提供了一个方法:void join()
- 该方法允许调用这个方法的线程在该方法所属线程上等待(阻塞),直到该方法所属线程结束后才会 解除等待继续后续的工作.所以join方法可以用来协调线程的同步运行.
- 同步运行:多个线程执行过程存在先后顺序进行.
- 异步运行:多个线程各干各的.线程本来就是异步运行的.
package thread;
/**
* 线程提供了一个join方法,可以协调线程的同步运行。它允许调用该方法的线程等待(阻塞),
* 直到该方法所属线程执行完毕后结束等待(阻塞)继续运行。
*
* 同步运行:多个线程执行存在先后顺序。
* 异步运行:多个线程各干各的,线程间运行本来就是异步的。
*/
public class JoinDemo {
//图片是否下载完毕
public static boolean isFinish = false;
public static void main(String[] args) {
/*
当一个方法的局部内部类中引用了这个方法的其他局部变量时,这个变量
必须是final的。
*/
// final boolean isFinish = false;
Thread download = new Thread(){
public void run(){
for(int i=1;i<=100;i++){
System.out.println("down:"+i+"%");
try {
Thread.sleep(50);
} catch (InterruptedException e) {
}
}
System.out.println("down:下载完毕!");
isFinish = true;
}
};
Thread show = new Thread(){
public void run(){
try {
System.out.println("show:开始显示文字...");
Thread.sleep(3000);
System.out.println("show:显示文字完毕!");
/*
显示图片前要等待download执行完毕
*/
System.out.println("show:开始等待download...");
download.join();//show线程阻塞,直到download执行完毕
System.out.println("show:等待download完毕!");
System.out.println("show:开始显示图片...");
if(!isFinish){
throw new RuntimeException("show:显示图片失败!");
}
System.out.println("show:显示图片完毕!");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
download.start();
show.start();
}
}
当多个线程并发操作同一临界资源,由于线程切换时机不确定,导致操作临界资源的顺序出现混乱严重时可能导致系统瘫痪.
临界资源:操作该资源的全过程同时只能被单个线程完成.
package thread;
/**
* 多线程并发安全问题
* 当多个线程并发操作同一临界资源,由于线程切换的时机不确定,导致操作顺序出现
* 混乱,严重时可能导致系统瘫痪。
* 临界资源:同时只能被单一线程访问操作过程的资源。
*/
public class SyncDemo {
public static void main(String[] args) {
Table table = new Table();
Thread t1 = new Thread(){
public void run(){
while(true){
int bean = table.getBean();
Thread.yield();
System.out.println(getName()+":"+bean);
}
}
};
Thread t2 = new Thread(){
public void run(){
while(true){
int bean = table.getBean();
/*
static void yield()
线程提供的这个静态方法作用是让执行该方法的线程
主动放弃本次时间片。
这里使用它的目的是模拟执行到这里CPU没有时间了,发生
线程切换,来看并发安全问题的产生。
*/
Thread.yield();
System.out.println(getName()+":"+bean);
}
}
};
t1.start();
t2.start();
}
}
class Table{
private int beans = 20;//桌子上有20个豆子
public int getBean(){
if(beans==0){
throw new RuntimeException("没有豆子了!");
}
Thread.yield();
return beans--;
}
}
sleep方法的使用可以用于以下情况:
守护线程的创建和启动方式与普通线程相同,只需在调用start()方法之前,使用setDaemon(true)方法将线程设置为守护线程。
守护线程的使用场景:
join方法可以用于以下情况:
join方法有两种重载方式:
需要注意的是,join方法只能在当前线程内部调用,即在run方法或其他线程内部调用join方法会导致程序死锁。
sleep方法用于暂停当前线程的执行一段时间,守护线程用于后台执行任务,join方法用于等待另一个线程执行完毕。