JAVA学习第二十八课(多线程(七))- 停止线程和多线程面试题

来源:互联网 发布:虚拟路由器软件 编辑:程序博客网 时间:2024/05/04 10:34


重点掌握

/*
 * wait 和 sleep 区别?
 * 1.wait可以指定时间也可以不指定
 * sleep必须指定时间
 * 2.在同步中,对CPU的执行权和锁的处理不同
 * wait释放执行权,释放锁    sleep释放执行权,不释放锁
 */

//同步里具备执行资格的线程不止一个,但是能得到锁的只有一个,所以能执行的也只有一个


一、停止线程的方式

不可能让线程一直在运行,所以需要让线程停止


1.定义循环结束标记

一般而言,线程运行代码都是循环的,只要控制了循环就可以结束任务

2.使用interrupt(中断)

结束线程的冻结状态,使线程回到运行状态

PS:stop过时了,不用了

第一种方式:(常用)

class StopThread implements Runnable{private boolean flag = true;public void run(){while(flag){System.out.println(Thread.currentThread().getName()+"---");}}public void ChangeFlag(){flag = false;}}public class Main{public static void main(String[] args){StopThread s = new StopThread();Thread t1 = new Thread(s);Thread t2 = new Thread(s);t1.start(); t2.start();int i = 0;while(true){if(++i == 20)//i达到20后结束所有线程{s.ChangeFlag();break;}System.out.println("Main.main"+i);}System.out.println("Final");}}

缺点:

class StopThread implements Runnable{private boolean flag = true;public synchronized void run(){while(flag){try {wait();} catch (InterruptedException e) {// TODO: handle exceptionSystem.out.println(Thread.currentThread().getName()+"..."+e);}System.out.println(Thread.currentThread().getName()+"-++--");}}public void ChangeFlag(){flag = false;}}

主线程结束了,t0 t1直接wait()了,如果线程处于了冻结状态,就无法读取标记,所以就引入了第二种结束线程的方式


第二种方式:interrupt

将线程从冻结状态强制恢复到运行状态中,使线程回到具备CPU执行资格的状态,但是会发生中断异常(InterruptException)

class StopThread implements Runnable{private boolean flag = true;public synchronized void run(){while(flag){try {wait();} catch (InterruptedException e) {// TODO: handle exceptionSystem.out.println(Thread.currentThread().getName()+"........."+e);flag = false;//注意处理,不加这个会导致线程继续等待,主线程结束t1 t2未结束}System.out.println(Thread.currentThread().getName()+"-++--");}}public void ChangeFlag(){flag = false;}}public class Main{public static void main(String[] args){StopThread s = new StopThread();Thread t1 = new Thread(s);Thread t2 = new Thread(s);t1.start(); t2.start();int i = 0;while(true){if(++i == 20)//i达到20后结束所有线程{//s.ChangeFlag();t1.interrupt();t2.interrupt();break;}System.out.println("Main.main"+i);}System.out.println("Final");}}


二、守护线程

setDaemon(boolean)

public class Main{public static void main(String[] args){StopThread s = new StopThread();Thread t1 = new Thread(s);Thread t2 = new Thread(s);t1.start(); t2.setDaemon(true);//守护线程,可以理解为后天线程//后天线程的特点:运行和前台线程一样,和CPU抢夺执行权//           结束:前台线程必须手动结束,后台线程如果所有的前提线程都结束了,后台线程也跟着结束t2.start(); int i = 0;while(true){if(++i == 20)//i达到20后结束所有线程{//s.ChangeFlag();t1.interrupt();//t2.interrupt();break;}System.out.println("Main.main"+i);}System.out.println("Final");}}

守护线程简单理解:比如说(英雄联盟)LOL,我方英雄需要守护我方的防御塔,塔没了,守护线程也就没必要存在了

三、线程的其他方法

1.join()

2.setPriority()


class Demo implements Runnable{public void run(){for(int i = 0;i<20;i++)System.out.println(Thread.currentThread().getName()+"..."+i);}}public class Main{public static void main(String[] args)throws Exception{Demo d = new Demo();Thread t1 = new Thread(d);Thread t2 = new Thread(d);t1.start();t1.join();//t1线程要申请加入进来,运行,也就是t1不完,t2 和 主线程 就不能执行,//临时假如一个线程,就要用join方法t2.start();//如果join放在t2.start()后面,那么主线程只等待t1完成后运行,而t1和t2互相争夺执行权for(int i = 0;i<20;i++)System.out.println(Thread.currentThread().getName()+".."+i);}}

优先级:setPriority

class Demo implements Runnable{public void run(){for(int i = 0;i<20;i++)System.out.println(Thread.currentThread().toString()+"..."+i);}}public class Main{public static void main(String[] args)throws Exception{Demo d = new Demo();Thread t1 = new Thread(d);Thread t2 = new Thread(d);t1.start();t2.start();t2.setPriority(Thread.MAX_PRIORITY);// Thread.MIN_PRIORITY优先级最小1//Thread.MAX_PRIORITY 有效级最大10//Thread.NORM_PRIORITY 默认优先级 5for(int i = 0;i<20;i++)System.out.println(Thread.currentThread()+".."+i);}}

3.线程组

把10个线程放一个组里,如果中断这一组线程,那么这10个线程都中断了

4.yield()暂停当前正在执行的线程,并执行其他线程


class Demo implements Runnable{public void run(){for(int i = 0;i<20;i++){System.out.println(Thread.currentThread().toString()+"..."+i);Thread.yield();}}}

public class Main{public static void main(String[] args)throws Exception{new Thread()//线程子类{public void run(){for(int i = 0;i<20;i++){ System.out.println(Thread.currentThread().getName()+"x = "+i);}}}.start();for(int i = 0;i<20;i++){ System.out.println(Thread.currentThread().getName()+"y = "+i);}Runnable r = new Runnable() {public void run() {for(int i = 0;i<20;i++){ System.out.println(Thread.currentThread().getName()+"z = "+i);}}};new Thread(r).start();}}

多线程面试题:

1.

class Text implements Runnable{public void run(Thread t){}}//是否编译失败?如果失败错误在哪?

失败,没有实现run方法的覆盖

改法一:

abstract class Text implements Runnable{public void run(Thread t){}}

改法二:重载,进行覆盖


class Text implements Runnable{public void run(){System.out.println("Text.run()1");}public void run(Thread t){System.out.println("Text.run()2");}}
2.

public class Main{public static void main(String[] args)throws Exception{new Thread(new Runnable() {public void run() {// TODO Auto-generated method stubSystem.out.println("Runnable run");}}){public void run(){System.out.println("Thread run");}}.start();//这段代码编译能通过吗?如果能打印哪一句}}
打印Thread run
以子类为主,没有子类以父类为主




0 0