一、程序,进程,线程
【1】程序,进程,线程
➢程序(program):是为完成特定任务、用某种语言编写的一组指令的集合,是一段静态的代码。 (程序是静态的)
➢进程(process):是程序的一次执行过程。正在运行的一个程序,进程作为资源分配的单位,在内存中会为每个进程分配不同的内存区域。 (进程是动态的)是一个动的过程 ,进程的生命周期 : 有它自身的产生、存在和消亡的过程
➢线程(thread),进程可进一步细化为线程, 是一个程序内部的一条执行路径。
若一个进程同一时间并行执行多个线程,就是支持多线程的。
【2】单核CPU与多核CPU的任务执行:
【3】并行和并发:
并行:多个CPU同时执行多个任务
并发:一个CPU“同时”执行多个任务(采用时间片切换)
二、创建线程的三种方式
- 第一种:继承Thread类
【1】在学习多线程一章之前,以前的代码是单线程的吗?不是,以前也是有三个线程同时执行的。
【2】现在我想自己制造多线程---》创建线程 ??
线程类--》线程对象
/**
* 线程类叫:TestThread,不是说你名字中带线程单词你就具备多线程能力了(争抢资源能力)
* 现在想要具备能力,继承一个类:Thread,具备了争抢资源的能力
*/
public class TestThread extends Thread{
/*
一会线程对象就要开始争抢资源了,这个线程要执行的任务到底是啥?这个任务你要放在方法中
但是这个方法不能是随便写的一个方法,必须是重写Thread类中的run方法
然后线程的任务/逻辑写在run方法中
*/
@Override
public void run() {
//输出1-10
for (int i = 1; i <= 10 ; i++) {
System.out.println(i);
}
}
}
/**
* 测试类
*/
public class Test {
//这是main方法,程序的入口
public static void main(String[] args) {
//主线程中也要输出十个数:
for (int i = 1; i <= 10 ; i++) {
System.out.println("main1-----"+i);
}
//制造其他线程,要跟主线程争抢资源:
//具体的线程对象:子线程
TestThread tt = new TestThread();
//tt.run();//调用run方法,想要执行线程中的任务 -->这个run方法不能直接调用,直接调用就会被当做一个普通方法
//想要tt子线程真正起作用比如要启动线程:
tt.start();//start()是Thread类中的方法
//主线程中也要输出十个数:
for (int i = 1; i <= 10 ; i++) {
System.out.println("main2-----"+i);
}
}
}
运行结果:
1)设置读取线程名字
【1】setName,getName方法来进行设置读取:
/**
* 线程类叫:TestThread,不是说你名字中带线程单词你就具备多线程能力了(争抢资源能力)
* 现在想要具备能力,继承一个类:Thread,具备了争抢资源的能力
*/
public class TestThread extends Thread{
/*
一会线程对象就要开始争抢资源了,这个线程要执行的任务到底是啥?这个任务你要放在方法中
但是这个方法不能是随便写的一个方法,必须是重写Thread类中的run方法
然后线程的任务/逻辑写在run方法中
*/
@Override
public void run() {
//输出1-10
for (int i = 1; i <= 10 ; i++) {
System.out.println(this.getName()+i);
}
}
}
/**
* 测试类
*/
public class Test {
//这是main方法,程序的入口
public static void main(String[] args) {
//给main方法这个主线程设置名字:
//Thread.currentThread()作用获取当前正在执行的线程
Thread.currentThread().setName("主线程");
//主线程中也要输出十个数:
for (int i = 1; i <= 10 ; i++) {
System.out.println(Thread.currentThread().getName()+"1-------"+i);
}
//制造其他线程,要跟主线程争抢资源:
//具体的线程对象:子线程
TestThread tt = new TestThread();
tt.setName("子线程");
//tt.run();//调用run方法,想要执行线程中的任务 -->这个run方法不能直接调用,直接调用就会被当做一个普通方法
//想要tt子线程真正起作用比如要启动线程:
tt.start();//start()是Thread类中的方法
//主线程中也要输出十个数:
for (int i = 1; i <= 10 ; i++) {
System.out.println(Thread.currentThread().getName()+"2-------"+i);
}
}
}
【2】通过构造器设置 名字:
/**
* 线程类叫:TestThread,不是说你名字中带线程单词你就具备多线程能力了(争抢资源能力)
* 现在想要具备能力,继承一个类:Thread,具备了争抢资源的能力
*/
public class TestThread extends Thread{
public TestThread(String name){
super(name);//调用父类的有参构造器
}
/*
一会线程对象就要开始争抢资源了,这个线程要执行的任务到底是啥?这个任务你要放在方法中
但是这个方法不能是随便写的一个方法,必须是重写Thread类中的run方法
然后线程的任务/逻辑写在run方法中
*/
@Override
public void run() {
//输出1-10
for (int i = 1; i <= 10 ; i++) {
System.out.println(this.getName()+i);
}
}
}
- 习题:买火车票
【1】原理:每个窗口都是一个线程对象:
【2】代码:
public class BuyTicketThread extends Thread {
public BuyTicketThread(String name){
super(name);
}
//一共10张票:
static int ticketNum = 10;//多个对象共享10张票
//每个窗口都是一个线程对象:每个对象执行的代码放入run方法中
@Override
public void run() {
//每个窗口后面有100个人在抢票:
for (int i = 1; i <= 100 ; i++) {
if(ticketNum > 0){//对票数进行判断,票数大于零我们才抢票
System.out.println("我在"+this.getName()+"买到了从北京到哈尔滨的第" + ticketNum-- + "张车票");
}
}
}
}
public class Test {
public static void main(String[] args) {
//多个窗口抢票:三个窗口三个线程对象:
BuyTicketThread t1 = new BuyTicketThread("窗口1");
t1.start();
BuyTicketThread t2 = new BuyTicketThread("窗口2");
t2.start();
BuyTicketThread t3 = new BuyTicketThread("窗口3");
t3.start();
}
}
- 第二种:实现Runnable接口
【1】代码:
/**
* TestThread实现了这个接口,才会变成一个线程类
*/
public class TestThread implements Runnable{
@Override
public void run() {
//输出1-10数字:
for (int i = 1; i <= 10 ; i++) {
System.out.println(Thread.curren