Java多线程常用方法的使用
Java多线程的常用方法基本分为:获取当前线程的操作,线程休眠sleep()方法,线程让步yield()方法,等待其他线程终止join()方法,线程停止的一系列方法。 一、获取当前线程的操作 ??1、获取当前线程: Thread.currentThread(); ????需要注意的是: 当一个线程A开启后,调用其他线程类B的普通方法时,此时的线程还是线程A, 当一个线程A直接调用另一个线程类B的run()方法,就和调用普通方法没有区别。 ??举个栗子说明run()和start()有十分明显的区别 package com.xiaoaxiao.test.thread_test.book_test; /** ?* Created by xiaoaxiao on 2019/7/16 ?* Description: run()和start()不一样!!! ?*/ class MyThread1 extends Thread{ ????@Override ????public void run() { ????????try { ????????????System.out.println("run threadName="+Thread.currentThread().getName()+" begin"); ????????????Thread.sleep(2000); ????????????System.out.println("run threadName="+Thread.currentThread().getName()+" end"); ????????} catch (InterruptedException e) { ????????????e.printStackTrace(); ????????} ????} } public class ThreadTest2 { ????public static void main(String[] args) { ????????MyThread1 mt = new MyThread1(); ????????System.out.println("begin ="+System.currentTimeMillis()); // ???????mt.run(); ????????mt.start(); ????????System.out.println("end ="+System.currentTimeMillis()); ????} } 若调用mt.run(),输出结果为: begin =1563329164153 run threadName=main begin run threadName=main end end =1563329166155 若调用mt.start(),输出结果为: begin =1563329194123 end =1563329194124 run threadName=Thread-0 begin run threadName=Thread-0 end ??2、获取当前线程的名字:Thread.currentThread().getName() ???而获取当前对象的名字(只在Thread的继承类中出现):this.getName() ??3、获取当前线程的唯一标识:Thread.currentThread().getId() 二、线程休眠sleep()方法—单位为毫秒(ms) ??线程休眠是指 让当前线程暂缓执行,等到了预计时间后再恢复执行。线程休眠会立即交出CPU,但是不会释放锁。 ??sleep()的流程:运行状态->sleep()->阻塞状态->sleep()的时间结束后->就绪状态->系统调度->运行状态。 ?? 虽然sleep()在指定时间可以从运行状态->(阻塞状态)->就绪状态,但是处于就绪状态时,需要经过系统的调度才能到达运行状态,具体的系统调度是随机的(由CPU进行控制),这就导致了每次sleep()的时间不相同(是有差异的)。 ??sleep()可能会抛出InterruptedException受查异常,需要对异常进行处理。 ??sleep()立即交出CPU,不会释放锁。 ??举个栗子 package com.xiaoaxiao.test.thread_test; /** ?* Created by xiaoaxiao on 2019/7/12 ?* Description: 测试thread常用的方法——sleep、 ?*/ class MyRunnable2 implements Runnable{ ????@Override ????public void run() { ????????for(int i=0;i<3;i++){ ????????????System.out.println(Thread.currentThread().getName()); ????????????// sleep() ????????????try { ????????????????Thread.sleep(1000); ????????????} catch (InterruptedException e) { ????????????????e.printStackTrace(); ????????????} ????????} ????} } public class threadMethodTest1 { ????public static void main(String[] args) { ????????MyRunnable2 myRunnable2 = new MyRunnable2(); ????????Thread thread1 = new Thread(myRunnable2,"A"); // ???????Thread thread2 = new Thread(myRunnable2,"hello"); ????????Thread thread2 = new Thread(myRunnable2,"B"); ????????Thread thread3 = new Thread(myRunnable2,"C"); ????????thread1.start(); ????????thread2.start(); ????????thread3.start(); ????} } 输出结果: B C A A C B B C A 三、线程让步yield()方法——运行态(running)->就绪态(runnable) ??线程让步是指 暂停执行当前的线程对象,并执行其他线程,yield()方法会让当前线程交出CPU(不一定立即交出CPU),不会释放锁。 ??yield()方法无法控制具体交出CPU的时间,并且yield()方法只能让拥有相同优先级的线程有获取CPU的机会 ??yield()会交出CPU(不一定立即交出),不会释放锁。 ??举个栗子 package com.xiaoaxiao.test.thread_test; /** ?* Created by xiaoaxiao on 2019/7/12 ?* Description: 测试thread常用的方法——yield ?*/ class MyRunnable2 implements Runnable{ ????@Override ????public void run() { ????????for(int i=0;i<10;i++){ ????????????System.out.println(Thread.currentThread().getName()); ????????????// yield() ????????????Thread.yield(); ????????} ????} } public class threadMethodTest1 { ????public static void main(String[] args) { ????????MyRunnable2 myRunnable2 = new MyRunnable2(); ????????Thread thread1 = new Thread(myRunnable2,"A"); ????????Thread thread2 = new Thread(myRunnable2,"C"); ?? ????????thread1.start(); ????????thread2.start(); ????????thread3.start(); ????} } 输出结果: A A A B B C C C B 四、等待其他线程终止join()方法 ??等待其他线程终止是指主线程等待子线程执行完成之后再结束。(主线程(或者某个线程)中若调用了子线程(或者是另外一个线程)的join()方法就必须得等该子线程run()方法结束,主线程才能继续执行) ?? join()方法只是对外汇代理Object提供的wait()做了一层包装而已。 (join在内部使用wait()方法进行等待),执行wait(long)方法后,当前线程的锁会被释放,其他线程就可以调用此线程中的同步方法了。 ?? join()方法的执行流程与sleep()类似:运行状态->join()->阻塞状态->join()中断->就绪状态->系统调度->运行状态。 ??join()可能会抛出InterruptedException受查异常,需要对异常进行处理。 ??join()会释放锁。 ??举个栗子 package com.xiaoaxiao.test.thread_test; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; /** ?* Created by xiaoaxiao on 2019/7/12 ?* Description: 测试thread常用的方法——join ?*/ class MyRunnable3 implements Runnable{ ????@Override ????public void run() { ????????try { ????????????System.out.println("主线程睡眠前时间"); ????????????threadMethodTest2.printTime(); ????????????Thread.sleep(1000); ????????????System.out.println(Thread.currentThread().getName()); ????????????System.out.println("睡眠结束时间"); ????????????threadMethodTest2.printTime(); ????????} catch (InterruptedException e) { ????????????e.printStackTrace(); ????????} ????} } public class threadMethodTest2 { ????public static void main(String[] args) throws InterruptedException { ????????MyRunnable3 myRunnable3 = new MyRunnable3(); ????????Thread threadA = new Thread(myRunnable3,"子线程A"); ????????System.out.println("代码开始"); ????????threadA.start(); ????????// 调用子线程的join方法,当主线程执行到这一步了, ????????// 一定会等到子线程中所有内容全部执行完,主线程才会继续往下执行 ????????threadA.join(); ????????System.out.println(Thread.currentThread().getName()); ????????System.out.println("代码结束"); ????} ????public static void printTime(){ ????????Date date = new Date(); ????????DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); ????????String time = format.format(date); ????????System.out.println(time); ????} } 输出结果为: 代码开始 主线程睡眠前时间 2019-09-27 16:56:26 子线程A 睡眠结束时间 2019-09-27 16:56:27 main 代码结束 ??还可以使用join(long)设置最长等待时间(单位:ms),若主线程等待long秒后,无论子线程会不会结束,此时join()中断,主线程进入就绪状态。 class Join extends Thread{ ????@Override ????public void run() { ????????try { ????????????System.out.println("begin Timer="+System.currentTimeMillis()); ????????????Thread.sleep(5000); ????????????System.out.println("end Timer="+System.currentTimeMillis()); ????????} catch (InterruptedException e) { ????????????e.printStackTrace(); ????????} ????} } public class JoinTest { ? ????public static void main(String[] args) { ????????Thread thread = new Join(); ????????thread.start(); ????????try { ????????????thread.join(2000); ????????????System.out.println("main end Timer:"+System.currentTimeMillis()); ????????} catch (InterruptedException e) { ????????????e.printStackTrace(); ????????} ????} } // 打印结果 begin Timer=1569575039934 end Timer=1569575041934 main end Timer:1569575041934 五、线程停止的一系列方法 ??1、设置标记位(flag)停止线程——推荐(好写) ?? 在线程类内部设置一个标记位flag并由这个flag对线程类的执行进行控制,在线程类的外部对flag进行修改,从而实现外部对类内部的停止。 package com.xiaoaxiao.test.thread_test; /** ?* Created by xiaoaxiao on 2019/7/12 ?* Description: 测试thread常用的方法——线程停止-设置标记符 ?*/ class MyRunnable4 implements Runnable{ ????// 设置一个标记符 ????private Boolean flag = true; ????@Override ????public void run() { ????????int i=1; ????????// 将该标记符当做线程持续进行的条件 ????????while (flag){ ????????????try { ????????????????Thread.sleep(1000); ????????????} catch (InterruptedException e) { ????????????????e.printStackTrace(); ????????????} ????????????System.out.println("这是第"+i+"次执行"+"线程名称为:" ???????????? +Thread.currentThread().getName()); ????????????i++; ????????} ????} ????public void setFlag(Boolean flag) { ????????this.flag = flag; ????} } public class threadMethodTest3 { ????public static void main(String[] args) throws InterruptedException { ????????MyRunnable4 myRunnable4 = new MyRunnable4(); ????????Thread thread = new Thread(myRunnable4); ????????thread.start(); ????????Thread.sleep(5000); ????????// 主线程睡眠5s后将flag设置为false, ????????// 当子线程再次访问是,flag已经变为false ????????myRunnable4.setFlag(false); ????????// 调用子线程的join,让主线程等待子线程执行完成后再执行 ????????thread.join(); ????????System.out.println("代码结束"); ????} } 2、调用Thread类的stop()方法强制停止线程,该方法不安全,已经被Deprecated(废弃)了。 ??该方法之所以不安全主要是会造成数据的不一致。 while(flag){ ?????????//按照第一种停止方式,即便在x=3后,flag变为了false, //y依旧能被赋值为4 x=3; y=4; } ?????????????????????//而如果在x=3后直接stop(),则y就不会被赋值为4了 3、调用Thread类的interrupt()方法——系统设置标志位 ①interrupt()方法只是将线程状态置为中断状态而已,它不会中断一个正在运行的线程,此方法只是给线程传递一个中断信号,程序可以根据此信号来判断是否需要终止。(使用isInterrupted()判断中断状态) ②当线程中使用wait()、sleep()、join()导致此线程阻塞,则interrupt()会在线程中抛出InterruptException,并且将线程的中断状态由true置为false。 PS:无论是在sleep()过程中,interrupt(),还是在interrupt()过程中,sleep(),都会抛出InterruptedException异常,并将interrupt中断状态置为false(sleep()和interrupt只要相遇就会出异常,其他两者同理) ③interrupt()中断线程 a)线程中没有wait(),sleep(),join(),调用interrupt只是将线程中断状态设置为true。 b)线程中有wait(),join(),调用interrupt会抛出InterruptException并将线程中断状态由true置为false,在catch块中捕获该异常,然后退出 ??举个栗子,sleep()对interrupt()的影响 package com.xiaoaxiao.test.thread_test.book_test; /** ?* Created by xiaoaxiao on 2019/7/16 ?* Description: sleep()对Interrupt()的影响 ?* ?????????????无论是在sleep()过程中,interrupt() ?* ?????????????还是在interrupt()过程中,sleep() ?* ?????????????都会抛出InterruptedException异常,并将interrupt状态置为false ?*/ class MyThread2 extends Thread{ ????@Override ????public void run() { ????????super.run(); ????????try { ????????????for(int i=0;i<1000000;i++){ ????????????????System.out.println("i="+(i+1)); ????????????} ????????????System.out.println("run begin"); ????????????Thread.sleep(200000); ????????????System.out.println("run end"); ????????} catch (InterruptedException e) { ????????????System.out.println("先停止,再遇到sleep,interrupt状态为:" ???????????? +this.isInterrupted()); ????????????e.printStackTrace(); ????????} ????} } public class InterruptTest { ????public static void main(String[] args) { ????????MyThread2 mt = new MyThread2(); ????????mt.start(); ????????mt.interrupt(); ????????System.out.println("end!"); ????} } ———————————————— 原文链接:https://blog.csdn.net/weixin_43490440/article/details/96202420 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |