21-多线程(一),线程创建,线程的状态
-
多线程概念:
- 程序: 是一个指令的集合(静态)
- 线程: 正在执行中的程序
- 线程是程序的一次静态执行的过程,占用特定的地址空间
- 每个线程都是独立的
- 进程: 一个进程可以拥有多个并行的线程
线程的创建:
两种:
1. 继承thread类 2. 实现Runnable接口
//1.继承thread类
public class Mythread extends Thread{ //具有了多线程的功能
@Override
public void run() { //重写,线程操作的代码
//run方法中的代码称之为线程体,(线程所有执行和的主题)
for(int i=0;i<10;i++) {
System.out.println(Thread.currentThread().getName()+"==="+i);
}
}
//构造方法
public Mythread(String name) {
super(name);
// TODO Auto-generated constructor stub
}
public Mythread() {
super();
// TODO Auto-generated constructor stub
}
}
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.println("请输入你的年龄: ");
//int age = input.nextInt(); //等待控制台输入年龄
//创建线程
Mythread my = new Mythread(); //创建一个线程对象
Mythread my1 = new Mythread();
Mythread my2 = new Mythread();
//my.run(); //对象点方法名
my1.start(); //启动一个线程
int age1 = input.nextInt();
my2.start(); //不可以重复调用
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+"===="+i);
}
//创建带有参数的线程对象
Mythread myy = new Mythread("线程一");
myy.start();
}
}
-
2.实现Runnable接口的类具有多线程的能力
建议使用接口的方式:
优点: 1. 可以避免java中类的单继承所带来的局限性
2.可以实现资源的共享
package deskdemo.demo2;
public class MyRun implements Runnable{
@Override
public void run() { //实现接口当中的方法,实现多线程的
// TODO Auto-generated method stub
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName()+"===="+i);
}
}
}
public class Test {
public static void main(String[] args) {
MyRun mr = new MyRun();
Thread t = new Thread(mr); //调用带参构造方法创建对象,参数是Runnable接口的实例
Thread t1 = new Thread(mr);
Thread t2 = new Thread(mr);
t.start();
t1.start();
t2.start();
}
}
-
多线程案例
有5张票,100个人在排队买票,分三个窗口都在排队买票,看下’继承Thread类的实现方式和实现Runnable接口的区别.
//继承Thread类的方式
public class MyTicket extends Thread{
private int ticket = 5; //有5张票
//重写run方法
public void run() {
for (int i = 0; i < 5; i++) { //有100个人在排队买这五张票
if(ticket>0) {
System.out.println(Thread.currentThread().getName()+"买票"+i);
}
}
}
}
public class Test {
public static void main(String[] args) {
//创建三个窗口买票,每个窗口都是100人
MyTicket m1 = new MyTicket();
MyTicket m2 = new MyTicket();
MyTicket m3 = new MyTicket();
m1.start();
m2.start();
m3.start();
}
}
//实现Runnable接口的方式
public class MyRun implements Runnable{
private int ticket = 5; //有5张票
//重写run方法
public void run() {
for (int i = 0; i < 5; i++) { //有100个人在排队买这五张票
if(ticket>0) {
System.out.println(Thread.currentThread().getName()+"买票"+i);
}
}
}
}
public class TestRun {
public static void main(String[] args) {
//三个窗口共享5张票,创建线程类的对象
MyRun mr = new MyRun();//创建一个线程类的对象,在堆中开辟一块空间,有一个属性ticket,值为5
//借助thread类去启动线程
Thread t1 = new Thread(mr);
Thread t2 = new Thread(mr);
Thread t3 = new Thread(mr);
t1.start();
t2.start();
t3.start();
}
}
- 线程的状态:
- 新生状态:
- 使用new关键字建立一个线程后,该线程就处于新生状态.
- 处于新生状态的线程有自己的内存空间,通过调用start()方法进入就绪状态.
- 就绪状态:
- 处于就绪状态的线程具备了运行的条件,但还没有分配到cpu,处于线程的就绪队列,等到 系统为其分配CPU资源
- 当系统选定一个等待执行的线程后,它就会从就绪状态进入到执行状态,该动作称之为CPU调度
- 运行状态:
- 在运行状态的线程执行自己的run方法中的代码,直到等到都资源而阻塞或者完成而死亡
- 如果在给定的时间片内没有执行结束,就会被系统给换下来回到等待执行状态
- 阻塞状态:
- 处于运行状态的线程在某些情况下,如执行了sleep方法后,等待I/O设备等资源,将让出CPU时停止自己的运行,进入阻塞状态
- 在阻塞状态的线程布恩那个进入就绪队列,只有当阻塞的原因消除后,如睡眠时间到了,或者I/O设备空闲下来,线程便转入就绪状态,重新到就绪队列中排队等待,被系统选中后从原来的停止的位置开始继续执行
- 死亡状态:
- 死亡状态是线程声明周期中的最后一个阶段,线程的死亡的原因有三个,一个是正常的线程完成了它所有的工作;另一个是线程被强制型的终止,如通过stop方法来终止一个线程(不推荐使用);三是线程抛出未捕获的异常.
- 新生状态: