一.线程概述
1.进程和线程的概念
进程:进程是操作系统结构的基础;是一次程序的执行;是一个程序及其数据在处理机上顺序执行时所发生的活动;是程序在一个数据集合上运行的过程,它是系统进行资源分配和调度的一个独立单位;进程是受操作系统管理的基本运行单元。
线程:可以理解成是在进程中独立运行的子任务;使用多线程也就是在使用异步。线程分为两种一种是用户线程,一种是守护线程;守护线程是一种特殊的线程,当进程中不存在非守护线程了,则守护线程自动销毁(垃圾回收线程),setDaemon(true)设置线程为守护线程。
2.创建线程的方式
- 继承Thread类
package chapter1.create; public class MyThread extends Thread{ @Override public void run() { super.run(); System.out.println("MyThread"); } }
package chapter1.create; public class Run { public static void main(String[] args) { MyThread myThread = new MyThread(); myThread.start(); System.out.println("end!"); } }
运行结果如下:
end!
MyThread
线程是一个子任务,CUP以不确定的方式,或者说是随机的时间来调用线程中的run方法,所以就会出现先打印end!,再打印MyThread了。
- 实现Runnable接口
package chapter1.create; public class MyRunnable implements Runnable{ @Override public void run() { System.out.println("运行中..."); } }
package chapter1.create; public class Run { public static void main(String[] args) { MyRunnable myRunnable = new MyRunnable(); Thread thread = new Thread(myRunnable); thread.start(); System.out.println("运行结束"); } }
运行结果:
运行结束
运行中...
Thread.java类也实现了Runnable接口,也就意味着Thread(myRunnable)可以传入一个Thread类的对象,这样做可以将一个Thread对象中的run方法交由其他的线程进行调用。
使用继承Thread类的方式创建线程时,最大的局限就是不支持多继承。
3.常用方法介绍
- currentThread()方法可返回代码段正在被哪个线程调用的信息。
package chapter1.create; public class MehthodCurrentThreadTest { static class CountOperate extends Thread{ public CountOperate() { System.out.println("CountOperate init----begin"); System.out.println("Thread.currentThread().getName()="+Thread.currentThread().getName()); System.out.println("this.getName()="+this.getName()); System.out.println("CountOperate init----end"); } @Override public void run() { super.run(); System.out.println("run----begin"); System.out.println("Thread.currentThread().getName()="+Thread.currentThread().getName()); System.out.println("this.getName()="+this.getName()); System.out.println("run----end"); } } public static void main(String[] args) { CountOperate countOperate = new CountOperate(); Thread t = new Thread(countOperate); t.setName("A"); t.start(); } }
运行结果:
CountOperate init----begin
Thread.currentThread().getName()=main
this.getName()=Thread-0
CountOperate init----end
run----begin
Thread.currentThread().getName()=A
this.getName()=Thread-0
run----end
- isAlive()判断当前的线程是否处于活动状态,活动状态就是线程已经启动且尚未终止。
- sleep()是在指定的毫秒数内让当前"正在执行的线程"休眠(暂停执行),这个"正在执行的线程"是指this.currentThread()返回的线程。
- getId()取得线程的唯一标识。
- yield()方法的作用是放弃当前的CPU资源,将它让给其他的任务去占用CPU执行时间。但放弃的时间不确定,有可能刚刚放弃,马上有获得CPU时间片。
- suspend():暂停,已废弃。会有独占和不同步的问题。
- resume():恢复,已废弃;会有独占和不同步的问题。
4.停止线程
判断线程是否为中断状态的方法:
- interrupted():当前线程是否已经是中断状态,当前线程指运行interrupted()方法的线程,执行后具有将状态标志清除为false的功能;
- public static boolean interrupted() {
return currentThread().isInterrupted(true);
}
- public static boolean interrupted() {
- isInterrupted():线程对象是否已经是中断状态,但不清除状态标志。
停止线程的方法:
- 使用interrupt方法中断线程,但方法并没有停止线程,只是将状态标志为中断,调用isInterrupted()将返回true。
package chapter1.create.threadinterrupt; public class MyThread extends Thread{ @Override public void run() { super.run(); for(int i=0;i<500000;i++) { System.out.println("i="+(i+1)+"interrupted------------"+this.isInterrupted()); } } }
package chapter1.create.threadinterrupt; public class Run { public static void main(String[] args) { try { MyThread myThread = new MyThread(); myThread.start(); Thread.sleep(2000); myThread.interrupt(); } catch (Exception e) { System.out.println("main catch."); e.printStackTrace(); } } }
运行结果:
i=499992interrupted------------true
i=499993interrupted------------true
i=499994interrupted------------true
i=499995interrupted------------true
i=499996interrupted------------true
i=499997interrupted------------true
i=499998interrupted------------true
i=499999interrupted------------true
i=500000interrupted------------true
在沉睡中停止:
package chapter1.create.threadinterrupt; public class StopWhenSleepTest { static class MyThread extends Thread{ @Override public void run() { super.run(); try { System.out.println("run begin"); Thread.sleep(200000); System.out.println("run end"); } catch (InterruptedException e) { System.out.println("进MyThread.java类run方法中的catch了。"+this.isInterrupted()); e.printStackTrace(); } } } public static void main(String[] args) { try { MyThread myThread = new MyThread(); myThread.start(); Thread.sleep(2000); myThread.interrupt(); } catch (Exception e) { System.out.println("main catch."); e.printStackTrace(); } System.out.println("Main end"); } }
运行结果:
run begin
Main end
进MyThread.java类run方法中的catch了。false
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at chapter1.create.threadinterrupt.StopWhenSleepTest$MyThread.run(StopWhenSleepTest.java:12)
如果在sleep状态下停止线程,会进入catch,并且清楚停止状态值,使之成为false。先interrupt再sleep也会进入catch,此处不做赘述。
- 异常法
package chapter1.create.threadinterrupt; public class StopThreadByExceptionTest { static class MyThread extends Thread{ @Override public void run() { super.run(); try { for(int i=0;i<500000;i++) { if(this.isInterrupted()) { System.out.println("已经是停止状态了!我要退出了"); throw new InterruptedException(); } System.out.println("i="+(i+1)); } } catch (InterruptedException e) { System.out.println("进MyThread.java类run方法中的catch了。"); e.printStackTrace(); } } } public static void main(String[] args) { try { MyThread myThread = new MyThread(); myThread.start(); Thread.sleep(2000); myThread.interrupt(); } catch (Exception e) { System.out.println("main catch."); e.printStackTrace(); } } }
运行结果:
i=420003
i=420004
i=420005
i=420006
i=420007
i=420008
i=420009
i=420010
i=420011
已经是停止状态了!我要退出了
进MyThread.java类run方法中的catch了。
java.lang.InterruptedException
at chapter1.create.threadinterrupt.StopThreadByExceptionTest$MyThread.run(StopThreadByExceptionTest.java:14)
- 使用return停止线程:判断this.isInterrupted()为true,return。不过还是建议使用“异常法”,因为在catch块中可以对异常的信息进行相关的处理,而且使用异常流能更好、更方便地控制程序的运行流程。
- stop()暴力停止。该方法已经被废弃,因为如果强制让线程停止则有可能使一些清理性的工作得不到完成。另外一个情况就是对锁定的对象“解锁”,导致数据得不到同步的处理,出现数据不一致的问题。
5.线程的优先级
setPriority(int priority):值的范围1-10,设置线程优先级有助于帮“线程规划器”确定在下一次选择哪一个线程来优先执行。
- 线程的优先级具有继承性,比如A线程启动B线程,则B线程的优先级与A是一样的。
- 线程的优先级具有一定的规则性,也就是CPU尽量将执行资源让个优先级较高的线程。
- 线程的优先级具有随机性,也就是优先级较高的线程不一定每一次都先执行。