? ?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方法用于等待另一个线程执行完毕。
? ? ??