Java中的线程
Java语言的一大特点就是内置了对多线程的支持.多线程是指同时存在几个执行体,按几条不同的执行线索共同工作的情况.
多线程的存在使得能够方便地开发出能同时处理多个任务的应用程序,其中可能会使我们产生一种错觉就是以为几个事件是同时发生一样,实际上不是的,这是由于Java快速地从一个线程切换到另一个线程而造成的
从下面的代码看出是有问题的,两个死循环实质上只能执行第一个,第二个循环是永远不会执行的
但是通过引入两个线程的话,第二个循环就有机会被执行
public class Example15_1 {
public static void main(String[] args) {
while(true){
System.out.println("hello");
}
while(true){ //不会执行
System.out.println("hi");
}
}
}
程序/进程/线程
首相理解程序
程序是一段静态的代码,他是应用软件执行的蓝本
而后理解进程
进程是程序的一次动态执行过程,它对应了从代码加载,执行至执行完毕的一个完整过程,这个过程也是进程本身从产生,发展至消忙的过程
最后到线程
线程就是比进程更小的执行单位
Java的多线程就是在操作系统每次分时给Java程序一个时间片的CPU时间内,在若干个独立的可控制的线程之间进行切换。如果机器有多个CPU处理器,那么JVM就能充分利用这些CPU,使得Java程序在同一时刻能获得多个时间片,Java程序就可以获得真实的线程并发执行效果。
线程的状态与生命周期
Java语言使用Thread类
及其子类的对象来表示线程,Thread提供getState()
方法返回枚举类型Thread.
下列就是枚举常量
- 新建状态(NEW)
新建的线程对象就是这种状态,此时它已经有了资源以及内存空间,没有调用start()
方法的线程也是处于这种状态 - 可运行状态(RUNNABLE)
处于NEW状态的线程一旦调用start()方法就会进入RUNNABLE状态,进入此状态JVM就会发现有一个新的进程在排队等待切换了,
如果该线程是Thread的子类,那么必须重写父类中的run()
方法,run()方法规定了该线程的使命 - 中断状态(BLOCKED / WAITING / TIMED_WAITING)
当RUNNABLE状态的线程让出CPU使用权是就会使得状态变为BLOCKED状态 //相当于遇到突发情况就停下来了
当线程使用CPU资源期间执行了sleep(int millsecond)方法后就会进入TIMED_WAITING状态 ,当经过millsecond秒后再次进入RUNNABLE状态 //相当于等待一个红灯
当线程调用wait()方法后就会进入WAITING状态,必须有线程调用notif()
方法通知它才会再次RUNNING - 死亡状态(TERMINATED)
一个线程执行完run()方法后进入TERMINATED状态
需要注意的是只有处于NEW状态的线程才能调用start()方法,否则就会出现异常
//
线程的调用与优先级
处于就绪状态的线程首先进入就绪队列等待CPU资源,同一时刻在排队的可能有多个
这时候Java虚拟机中的线程调度器负责管理线程,调度器把线程分为10级,分别用Thread类中的类常量来表示,每个Java线程优先级都为常数1-10 表示,没有明确规定的话每个线程都是5级,但可以线程可以通过setPriority(int grade)
方法来设置优先级,需要注意的是有些系统只能识别1,5,10,三个级别
在实际编程中不提倡使用线程的优先级来保证算法的正确执行
用Thread的子类创建线程
在编写Thread类的子类是,需要重写父类的run()
方法,其目的规定线程的具体操作,否则线程不知道干什么,run()方法在父类中是没有任何语句的
线程中有setName(String str)
方法设置线程的名称
通过getName()
方法可以获取线程的名称
通过例子来体会一下
class Person extends Thread { //创建一个线程的子类
StringBuffer stringBuffer;
Person() {
}
Person(String name, StringBuffer stringBuffer) {
setName(name); //线程中的方法setName()设置线程的名称
this.stringBuffer = stringBuffer;
}
@Override
public void run() {
for (int i = 0; i < 4; i++) {
getName(); //获取线程中的名称
stringBuffer.append(getName() + ",");
System.out.println("我是" + getName() + ",字符串为:" + stringBuffer);
try {
Thread.sleep(200); //延迟0.2秒
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class Example15_1 {
public static void main(String[] args) {
StringBuffer stringBuffer = new StringBuffer(); //共享线程str
Person hong = new Person("小红", stringBuffer);
Person ming = new Person("小明", stringBuffer);
hong.start(); //开始线程
ming.start();
}
}
运行结果(每一次运行的结果都不一样,因为不知道线程每次都先将CPU分给谁)
C:\Users\Administrator\.IntelliJIdea2019.3\config\jdbc-drivers\MySQL Connector\J 8\8.0.15\mysql-connector-java-8.0.15.jar;C:\Users\Administrator\.IntelliJIdea2019.3\config\jdbc-drivers\Apache Derby\10.14.1.0\derby-10.14.1.0.jar" Chapter_15.Part_1.Example15_1
我是小红,字符串为:小明,小红,
我是小明,字符串为:小明,小红,
我是小红,字符串为:小明,小红,小红,
我是小明,字符串为:小明,小红,小红,小明,
我是小明,字符串为:小明,小红,小红,小明,小明,
我是小红,字符串为:小明,小红,小红,小明,小明,小红,
我是小明,字符串为:小明,小红,小红,小明,小明,小红,小明,小红,
我是小红,字符串为:小明,小红,小红,小明,小明,小红,小明,小红,
进程已结束,退出代码 0
CET4P195
- commence
- collaborate
- triple
- doom
- fluctuate
- masterpiece
- strive
- narrate
- gender
- curb
- expressway
- irrational
- betray
- counterpart
- ballot