进程(process)
是程序的一次执行过程,或是正在运行的一个程序。
线程(thread)
进程可进一步细化为线程,是一个程序内部的一条执行路径。
(1)多线程概念如果在一个进程中同时运行了多个线程,用来完成不同的工作,则称之为"多线程".(多个线程交替占用CPU资源,而非真正的并行执行)
多线程作用:让多部分代码同时执行;
(2)多线程好处
- 让多部分代码同时执行
- 带来良好的用户体验
- 充分利用CPU的资源
- 简化编程模型
缺点:导致程序运行效率降低。
(3)Thread类(4)主线程Java提供了java.lang.Thread类支持多线程编程
- main()方法即为主线程入口
- 产生其他子线程的线程
- 必须最后完成执行,因为它执行各种关闭动作
使用currentThread()方法获取当前线程的对象,是一个静态方法,返回一个Thread对象;
Thread t = Thread.currentThread();
- 获取主线程名getName();
- 设置主线程名setName();
public class Demo1 {
public static void main(String[] args) {
//1.获取主线程对象
Thread t = Thread.currentThread();
System.out.println("当前线程是:"+t.getName());
t.setName("MyJavaThread");
System.out.println("当前线程是:"+t.getName());
}
}
(5)继承Thread类创建线程
- 定义类继承Thread类;
- 覆盖Thread类中的run方法。
- 创建Thread子类对象,即创建了线程对象。
- 调用线程对象start方法(启动线程,调用run方法);
//1继承线程类
public class Dog extends Thread {
private String name;
public Dog(String name) {
super();
this.name = name;
}
// 2重写run方法
@Override
public void run() {
for (int i = 1; i <= 20; i++) {
System.out.println(name + "跑了第" + i + "圈");
}
}
}
/** * 继承Thread类创建多线程 * 步骤: * 1.定义类,继承Thread类; * 2.覆盖Thread类中的run方法; * 3.创建Thread子类对象(即线程对象); * 4.调用start方法开启线程,并调用线程的run方法执行; * @Hudie */
public class ThreadDemo2 {
public static void main(String[] args) {
//3创建Thread子类对象
Dog d1 = new Dog("花花");
Dog d2 = new Dog("小黄");
//4调用start方法
d1.start();
d2.start();
// d1.run();
// d2.run();
}
}
执行结果:
多个线程交替执行,不是真正的"并行";
线程每次执行时长由分配的CPU时间片长度决定;
启动多线程直接调用run()方法会怎样?
①:调用run()方法整个线程只有一条执行路径:
②:调用start()方法就是开启了多个子线程,多个子线程和主线程并行交替执行.
(6)实现Runnable接口创建线程
- 定义一个类实现Runnable接口;
- 覆盖接口中的run方法;
- 通过Thread类建立线程对象,并将Runnable接口的子类对象作为Thread类的构造函数的参数传递进来;
- 调用Thread类的start方法开启线程;
//①定义一个类实现Runnable接口;
public class Cat implements Runnable {
private String name;
public Cat(String name) {
super();
this.name = name;
}
// ②覆盖接口中的run方法
@Override
public void run() {
for (int i = 1; i <= 20; i++) {
System.out.println(name + "跑了第" + i + "圈");
}
}
}
public class ThreeadDemo3 {
public static void main(String[] args) {
// ③通过Thread类建立线程对象
Cat c1 = new Cat("小花猫");// 相当于Thread c11 = new Thread(c1);
Cat c2 = new Cat("小黑猫");
// ④调用线程对象的start方法开启线程;
new Thread(c1).start();
new Thread(c2).start();
}
}
(7)比较两种创建线程的方式
继承Thread类:
- 编写简单,可直接操作线程;
- 适用于单继承
实现Runnable接口(推荐使用):
- 避免单继承局限性;
- 便于共享资源;
(8)线程的五种状态
public class MyRunnable2 implements Runnable {
public void run() {
System.out.println("线程t正在运行!");
try {
Thread.sleep(500);
System.out.println("线程t休眠,处于阻塞状态!");
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println("线程t被中断");
}
}
public static void main(String[] args) {
Thread th = new Thread(new MyRunnable2(), "th");
System.out.println("线程t处于新建状态!");
th.start();
System.out.println("线程t处于就绪状态!");
}
}
在新建状态可以为线程设置线程名字,优先级;
一旦调用start方法,线程就处于就绪状态;
当获取到cup资源立刻转去调用run()方法执行线程体(此时是运行状态);
运行时可能被阻塞,进程被休眠;
线程执行完毕时,线程就死亡了;
(9)线程优先级
按照特定机制为多个线程分配CPU的使用权;
线程调度的方法:
setPriority(int grade);//设置线程优先级
sleep(long millis);//线程休眠(单位毫秒)
join();//线程强制执行(暂停当前线程,直到其他线程执行完毕再执行)
yield();//线程礼让(仅仅是提供一个可能)
设置线程优先级 线程优先级由1~10表示,1最低,默认优先级为5
优先级高的线程获得CPU资源的概率较大
public class Test {
public static void main(String[] args) {
Thread t1 = new Thread(new MyRunnable(), "线程A");
Thread t2 = new Thread(new MyRunnable(), "线程B");
t1.setPriority(Thread.MAX_PRIORITY);
t1.setPriority(Thread.MIN_PRIORITY);
t1.start();
t2.start();
}
}
public class MyRunnable implements Runnable {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}
这样后,线程A的优先级会明显变高,线程B的优先级变低
(10)线程休眠和强制执行
线程休眠
public static void sleep (long millis)
- 让线程暂时睡眠指定时长,线程进入阻塞状态;
- 睡眠时间过后线程会再进入可运行状态;
- 调用sleeo()方法需处理InterruptedException异常;
public class Wait {
public static void bySec(long s){
for(int i = 0;i<s;i++)
{
System.out.println(i+1+"秒");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public class Test2 {
public static void main(String[] args) {
System.out.println("------------主线程开始休眠------------");
Wait.bySec(5);//主线程休眠5秒;
System.out.println("----------主线程休眠结束-----------");
}
}
}
测试结果:
强制执行
public final void join();
public final void join(long mills); public
final void join(long mills,int nanos);
- millis:以毫秒为单位的等待时长;
- nanos:要等待的附加纳秒时长;
- 需处理InterruptedException异常;
package may_30th;
/** * 测试join() * @author mayn */
public class ThreadJoinDemo {
public static void main(String[] args) {
System.out.println("*******线程强制执行*******");
// 1.创建线程对象;
Thread temp = new Thread(new MyRunnable(), "temp");
temp.start();
for (int i = 0; i < 20; i++) {
// 当主线程执行到i==5时,暂停主线程,让子线程temp执行完毕之后主线程再执行
if (i == 5) {
try {
temp.join();// 强制执行temp线程
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "运行:" + i);
}
}
}
package may_30th;
public class MyRunnable implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "运行:" + i);
}
}
}
测试结果:
开始时主线程和子线程交替执行,当开始强制执行子线程时,主线程休眠,待到子线程执行完毕后,主线程再执行;
(11)线程的礼让(效果不明显)
Public static void yield();
- 暂停当前线程,允许其他具有相同优先级的线程获得运行机会;
- 该线程处于就绪状态,不转为阻塞状态;
- 只是提供一种可能,但是不能保证一定会实现礼让;
线程礼让测试:
package may_31th;
public class MyRunnable implements Runnable {
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + "运行:" + i);
// 当i==3时,线程礼让,当前线程将cpu资源让出;
if (i == 3) {
Thread.yield();
System.out.print("线程礼让:");
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
package may_31th;
public class Test {
public static void main(String[] args) {
Thread t1 = new Thread(new MyRunnable(), "线程A");
Thread t2 = new Thread(new MyRunnable(), "线程B");
t1.start();
t2.start();
}
}
测试结果:
结果显示:开始时线程AB交替运行,当B运行到三时,开始礼让,线程A得到了cpu资源,运行一次后也到了3,线程A开始礼让,走线程B…
(12)线程中断
interrupt()线程中断执行;