线程常用方法(二)
后台线程:
说明:后台进程也成为守护进程,通过调用setDaemon(true)设置为后台进程。主线程默认为前台线程。
特征:如果前台进程都死亡,后台进程会自动死亡。
注意:setDaemon(true)必须在start()方法之前调用,否则会引发异常IllegalThreadStateException异常
示例代码:
package method; /** * @Author YangHe * @Date 2020/4/8 17:51 * 目的:其他进程执行完成,守护进程自动消亡,不管守护进程是否执行完毕 */ public class ThreadDaemon extends Thread{ public ThreadDaemon(String name){ super(name); //设置线程名字 } @Override public void run() { for(int i=0;i<10;i++){ if(i==8&&getName().equals("守护线程")){ //如果是守护进程,睡眠保证执行进程先完成 try { sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(getName()+"输出"+i); } } public static void main(String[] args) throws InterruptedException { ThreadDaemon threadDaemon=new ThreadDaemon("守护线程"); ThreadDaemon threadDaemon2=new ThreadDaemon("执行线程"); threadDaemon.setDaemon(true); //将进程设置为守护进程 threadDaemon.start(); threadDaemon2.start(); } }
示例结果:
线程等待:join
说明:Thread提供了一个让一个线程等待另外一个线程完成的方法 join,调用join()方法,其他线程进入阻塞状态,等待该线程之执行完成,再进入就绪状态。
解决的实际问题:将一个大问题划分为许多小问题,每个小问题分配一个线程,这样所有小问题都解决完成,主线程来进行进一步不解决。
示例代码:
package method; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; /** * @Author YangHe * @Date 2020/4/8 16:34 * 目的:线程壹号等待线程贰号执行完毕开始执行 */ public class ThreadJoin implements Callable{ @Override public Integer call() throws Exception { int i=0; for(;i<100;i++){ System.out.println(Thread.currentThread().getName()+" 线程执行完成度 i "+i); } return i; } public static void main(String[] args) throws InterruptedException, ExecutionException { ThreadJoin threadJoin=new ThreadJoin(); FutureTask futureTask=new FutureTask (threadJoin); FutureTask futureTask2=new FutureTask (threadJoin); for(int j=0;j<100;j++){ if(j==50){ Thread thread=new Thread(futureTask,"线程壹号"); Thread thread2=new Thread(futureTask2,"线程贰号"); thread2.start(); thread2.join();//等待该线程执行完毕才往下执行 thread.start(); System.out.println("线程壹号等待线程贰号完成开始执行。。。"); } } System.out.println("线程贰号输出返回值:"); System.out.println(futureTask2.get()); } }
示例结果【可看出最后才输出返回值】:
线程睡眠:sleep
说明:让当前线程暂停一段时间,让出处理器资源,进入阻塞状态。
当睡眠时间达到,该进程将会重新进入就绪状态。
示例代码:
package method; /** * @Author YangHe * @Date 2020/4/8 16:18 * 目的:实现到一定的程度进行睡眠,让出资源让其他线程执行 */ public class ThreadSleep extends Thread { public ThreadSleep(String name){ super(name); //定义线程名称 } @Override public void run() { super.run(); for(int i=0;i<100;i++){ System.out.println(getName()+"i的值为 "+i); if(i==50){ System.out.println(getName()+"线程进入睡眠"); try { Thread.sleep(1000); //当i的值为50时随眠一秒,让出处理器资源,进入阻塞。 } catch (InterruptedException e) { e.printStackTrace(); }finally { System.out.println(getName()+"线程睡眠结束"); } } } } public static void main(String[] args) { ThreadSleep threadSleep=new ThreadSleep("线程壹号"); ThreadSleep threadSleep2=new ThreadSleep("线程贰号"); threadSleep.start(); threadSleep2.start(); } }
示例结果:
线程让步:yield
说明:只有其他线程优先级与当前线程优先级相同或者更高,才会获得执行机会。
设置线程优先级方法setPriority()
该方法和sleep方法相似,区别在于:
- sleep()方法暂停线程不会理会优先级,而yield只会给优先级相同或者更高的线程。
- sleep()方法让线程进入阻塞状态,而yield()方法让线程再次进入就绪状态,不会阻塞。可能该执行完yield()方法,立即再次获得处理器资源被执行。
- sleep()方法声明抛出异常InterruptedException异常,所以调用sleep()方法时要么捕获该异常,要么显式声明抛出异常。而yield()方法则没有声明抛出任何异常。
- sleep()比yield()有更好的移植性,通常不建议使用yield()方法来控制并发线程的执行。
示例代码:
package method; /** * @Author YangHe * @Date 2020/4/8 17:16 * 目的:级别低的线程给级别高的线程进行让步 */ public class ThreadYield extends Thread{ public ThreadYield(String name){ super(name); } @Override public void run() { for(int i=0;i<100;i++){ System.out.println(getName()+"当前执行i "+i); if(i==20){ System.out.println(getName()+"执行线程让步"); } } } public static void main(String[] args) { ThreadYield threadYield=new ThreadYield("最小线程级别"); threadYield.setPriority(MIN_PRIORITY); threadYield.start(); ThreadYield threadYield2=new ThreadYield("最大线程级别"); threadYield2.setPriority(MAX_PRIORITY); threadYield2.start(); } }
示例结果: