多线程的主要操作方法都在Thread类中定义,即分析理解Thread类中所定义的方法及使用。
1、线程的命名和取得
未命名状态下的线程运行是无序和不可确定的,当要抽取其中某个特定的线程时,此时就必须用到线程的命名方法。即,给一个目标线程取个名字,通过该名字可以在众多线程里找到目标线程。
线程的命名和取得名字的方法:
构造方法设置名字public Thread(Runnable target,String name)setName设置名字public final String getName()getName获取名字public final void setName(String name)若要获取给线程取得名字,应该使用currentThread()获取当前线程。
获得当前线程的方法 public static Thread currentThread()通过范例观察
代码结果package cn.demos;
class MyThread implements Runnable {
@Override public void run() { // 若要获取给线程取得名字,应该使用currentThread()获取当前线程。 System.out.println("当前线程:" + Thread.currentThread().getName()); } }
public class Demo1 { public static void main(String[] args) throws Exception {
MyThread mt = new MyThread(); new Thread(mt, "线程A").start(); // 设置线程名字 new Thread(mt).start(); new Thread(mt, "线程B").start(); } }
当前线程:线程A 当前线程:线程B 当前线程:Thread-0从以上程序可以发现,当开发者为线程设置名字时,获取的是开发者设置的名字,而未设置名字的线程,系统会自动给每个线程设置一个不重复的名字。
2、线程休眠
希望目标线程能够暂缓执行,休眠方法如下:
方法休眠方法1public static void sleep(long millis) throws InterruptedException休眠方法2public static void sleep(long millis, int nanos) throws InterruptedExceptionInterruptedException:表示中断异常
1)范例:观察休眠处理
代码结果package cn.demos;
public class Demo1 { public static void main(String[] args) throws Exception {
new Thread(() -> { for (int x = 0; x < 10; x++) { System.out.println(Thread.currentThread().getName() + "、x= " + x); try { // 暂缓执行 Thread.sleep(100); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }, "线程对象").start(); } }
线程对象、x= 0 线程对象、x= 1 线程对象、x= 2 线程对象、x= 3 线程对象、x= 4 线程对象、x= 5 线程对象、x= 6 线程对象、x= 7 线程对象、x= 8 线程对象、x= 9在程序执行过程中,可以明显看到每个线程的运行速度降低,所以休眠的主要特点是可以自动实现线程的唤醒,以继续进行后续处理。
注意:当有多个线程对象时,线程的休眠也具有先后顺序
2)范例:产生多个线程对象进行休眠处理
代码结果第一种方式package cn.demos;
public class Demo1 { public static void main(String[] args) throws Exception {
for (int num = 0; num < 5; num++) {
new Thread(() -> {
for (int x = 0; x < 10; x++) { System.out.println(Thread.currentThread().getName() + "、x= " + x); try { // 暂缓执行 Thread.sleep(100); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }, "线程对象=====" + num).start(); } } }
线程对象=====0、x= 0 线程对象=====4、x= 0 线程对象=====1、x= 0 线程对象=====3、x= 0 线程对象=====2、x= 0 线程对象=====2、x= 1 线程对象=====1、x= 1 线程对象=====0、x= 1 线程对象=====4、x= 1 线程对象=====3、x= 1 线程对象=====4、x= 2 线程对象=====0、x= 2 线程对象=====2、x= 2 线程对象=====1、x= 2 线程对象=====3、x= 2 线程对象=====4、x= 3 线程对象=====1、x= 3 线程对象=====2、x= 3 线程对象=====0、x= 3 线程对象=====3、x= 3 线程对象=====0、x= 4 线程对象=====2、x= 4 线程对象=====1、x= 4 线程对象=====4、x= 4 线程对象=====3、x= 4 线程对象=====4、x= 5 线程对象=====2、x= 5 线程对象=====0、x= 5 线程对象=====1、x= 5 线程对象=====3、x= 5 线程对象=====4、x= 6 线程对象=====2、x= 6 线程对象=====1、x= 6 线程对象=====0、x= 6 线程对象=====3、x= 6 线程对象=====0、x= 7 线程对象=====4、x= 7 线程对象=====1、x= 7 线程对象=====2、x= 7 线程对象=====3、x= 7 线程对象=====1、x= 8 线程对象=====2、x= 8 线程对象=====0、x= 8 线程对象=====4、x= 8 线程对象=====3、x= 8 线程对象=====1、x= 9 线程对象=====2、x= 9 线程对象=====0、x= 9 线程对象=====4、x= 9 线程对象=====3、x= 9第二种方式package cn.demos;
public class Demo1 { public static void main(String[] args) throws Exception {
Runnable run =() -> { for (int x = 0; x < 10; x++) { System.out.println(Thread.currentThread().getName() + "、x= " + x); try { // 暂缓执行 Thread.sleep(100); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }; for(int num = 0;num < 5;num++){ new Thread(run,"线程对象=====" + num).start(); } } }
观察程序运行得出,发现有几个对象就有几个线程是一起进行休眠,而后一起进了自动唤醒,而其实是有差别,只是细微的时间差,每个对象还是分先后进行。
3、线程中断
在线程休眠中发现一个“InterruptedException”中断异常,就可以得知线程的休眠是可以被打断的,而这种打断是被其他线程完成的。
中断执行方法:
方法判断线程是否被中断 public boolean isInterrupted() 中断线程执行 public void interrupt()范例:观察线程的中断处理操作
代码结果package cn.demos;
public class Demo1 { public static void main(String[] args) throws Exception {
Thread thread = new Thread(() -> { System.out.println("三天不睡觉的我需要睡觉补充精力"); // 休息10s try { Thread.sleep(10000); } catch (Exception e) { // 若线程被中断,会报一个中断异常 System.out.println("睡觉被打扰,强行起床"); } }); // 开始休息 thread.start(); // 出于人性化,可以让他先休息1s thread.sleep(1000); // 该判断线程是否中断 -------睡觉是否被打扰 if (!thread.isInterrupted()) { // 若没被中断,执行中断操作-----若无人打扰睡觉,我就去手动晃醒他,不让他睡觉 System.out.println("在睡觉的人旁边跳广场舞"); thread.interrupt(); } } }
三天不睡觉的我需要睡觉补充精力 在睡觉的人旁边跳广场舞 睡觉被打扰,强行起床结论:所有在执行的线程都是可以被中断的,而中断线程,都必须进行异常处理
4、线程强制运行
当满足于某些条件之后,某一个线程对象可以一直独占资源,一直到该线程的程序结束。
1)范例:观察正常线程
代码结果package cn.demos;
public class Demo1 { public static void main(String[] args) throws Exception {
Thread thread = new Thread(() -> { for (int x = 0; x < 10; x++) { System.out.println(Thread.currentThread().getName() + "执行、x=" + x); } }, "正常的线程"); thread.start();
for (int y = 0; y < 10; y++) { System.out.println("main的线程、y=" + y); } } }
main的线程、y=19 main的线程、y=20 main的线程、y=21 main的线程、y=22 main的线程、y=23 main的线程、y=24 main的线程、y=25 main的线程、y=26 正常的线程执行、x=2 main的线程、y=27 正常的线程执行、x=3 main的线程、y=28 正常的线程执行、x=4 main的线程、y=29 正常的线程执行、x=5 main的线程、y=30 正常的线程执行、x=6 正常的线程执行、x=7 正常的线程执行、x=8 正常的线程执行、x=9从以上程序可以看出,两个线程会交替进行,互相抢占资源,直到执行完毕。若此时希望main线程独自占用资源,等main执行完毕后才执行正常的,此时可以使用以下方法进行强制执行:
强制执行public final void join() throws InterruptedException2)范例:观察强制执行
代码结果package cn.demos;
public class Demo1 { public static void main(String[] args) throws Exception {
// 获得主线程 Thread mainThread = Thread.currentThread(); Thread thread = new Thread(() -> { for (int x = 0; x < 100; x++) { // 当X>3时,只允许main线程执行,且执行完毕后才能运行其他线程 if (x == 3) { // 执行强制线程 try { mainThread.join(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } ; } System.out.println(Thread.currentThread().getName() + "执行、x=" + x); } }, "正常的线程");
thread.start();
for (int y = 0; y < 100; y++) {
System.out.println("main的线程、y=" + y);
} } }
main的线程、y=0 正常的线程执行、x=0 main的线程、y=1 main的线程、y=2 main的线程、y=3 main的线程、y=4 main的线程、y=5 main的线程、y=6 main的线程、y=7 main的线程、y=8 main的线程、y=9 正常的线程执行、x=1 正常的线程执行、x=2 main的线程、y=10 main的线程、y=11 main的线程、y=12 main的线程、y=13 main的线程、y=14 main的线程、y=15 main的线程、y=16 main的线程、y=17 main的线程、y=18 main的线程、y=19 main的线程、y=20 main的线程、y=21 main的线程、y=22 main的线程、y=23 main的线程、y=24 main的线程、y=25 main的线程、y=26 main的线程、y=27 main的线程、y=28 main的线程、y=29 main的线程、y=30注意:在线程强制执行的时候,一定要获取强制执行线程对象之后才可以执行join()方法。
5、线程礼让
线程的礼让指的是将资源先让出去,让别的线程先使用资源。
线程礼让方法:
线程礼让yieldpublic static void yield()范例:线程的礼让操作
代码结果package cn.demos;
public class Demo1 { public static void main(String[] args) throws Exception {
Thread thread = new Thread(() -> { for (int x = 0; x < 100; x++) { if (x % 3 == 0) { // 线程礼让 Thread.yield(); System.out.println("!!!!正常线程礼让执行!!!"); } try { Thread.sleep(100); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "执行、x=" + x); } }, "正常的线程");
thread.start();
for (int y = 0; y < 100; y++) { Thread.sleep(100); System.out.println("main的线程、y=" + y);
} } }
!!!!正常线程礼让执行!!! main的线程、y=0 正常的线程执行、x=0 正常的线程执行、x=1 main的线程、y=1 正常的线程执行、x=2 main的线程、y=2 !!!!正常线程礼让执行!!! 正常的线程执行、x=3 main的线程、y=3 正常的线程执行、x=4 main的线程、y=4 main的线程、y=5 正常的线程执行、x=5 !!!!正常线程礼让执行!!! 正常的线程执行、x=6 main的线程、y=6 main的线程、y=7 正常的线程执行、x=7 正常的线程执行、x=8 main的线程、y=8 !!!!正常线程礼让执行!!! main的线程、y=9 正常的线程执行、x=9 正常的线程执行、x=10 main的线程、y=10 正常的线程执行、x=11 !!!!正常线程礼让执行!!! main的线程、y=11注意:每一次调用yield()方法都只会礼让一次当前的资源。
6、线程优先级
从理论上来讲,线程的优先级越高越有可能先执行(即越有可能先抢占到资源)。
优先级操作方法:
方法设置优先级 public final void setPriority(int newPriority) 获取优先级 public final int getPriority()从上面的方法定义中可以得出,优先级定义时都是通过int型数字来完成。
Thread类中定义优先级的常量:
名称描述定义对应的值MIN_PRIORITY最低优先级 public static final int MIN_PRIORITY 1NORM_PRIORITY中等优先级 public static final int NORM_PRIORITY 5MAX_PRIORITY最高优先级 public static final int MAX_PRIORITY 101)范例:观察优先级
代码结果package cn.demos;
public class Demo1 { public static void main(String[] args) throws Exception {
Runnable run = () -> { for (int x = 0; x < 10; x++) { try { Thread.sleep(100); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "执行,"); } }; Thread threadA = new Thread(run, "线程对象A"); Thread threadB = new Thread(run, "线程对象B"); Thread threadC = new Thread(run, "线程对象C"); // 设置优先级 threadA.setPriority(Thread.MIN_PRIORITY); threadB.setPriority(Thread.MIN_PRIORITY); threadC.setPriority(Thread.MAX_PRIORITY); // 执行 threadA.start(); threadB.start(); threadC.start(); } }
线程对象C执行, 线程对象B执行, 线程对象A执行, 线程对象A执行, 线程对象C执行, 线程对象B执行, 线程对象C执行, 线程对象A执行, 线程对象B执行, 线程对象C执行, 线程对象A执行, 线程对象B执行, 线程对象A执行, 线程对象C执行, 线程对象B执行, 线程对象C执行, 线程对象A执行, 线程对象B执行, 线程对象C执行, 线程对象A执行, 线程对象B执行, 线程对象A执行, 线程对象C执行, 线程对象B执行, 线程对象C执行, 线程对象A执行,注意:优先级并不是绝对的!!!
2)主线程优先级
代码结果package cn.demos;
public class Demo1 { public static void main(String[] args) throws Exception { System.out.println(Thread.currentThread().getPriority()); } }
5由以上程序可以得出,主线程的优先级属于中等优先级,而默认的线程优先级也是中等优先级。