线程的基本语法
1.线程的概念
①概念
一个软件就是一个进程,软件中的某个具体功能相当于一个线程,进程:可以看成是在计算机当中运行的一块代码,线程:可以看成是在计算机当中运行的一小块代码
②线程与进程的关系
- 一个进程中可以有多个线程,至少得有一个线程;
- 上面说一个进程可以狭隘的看成是一大段代码,那其实线程也是一段代码
- 线程是进程中的最小单位;
- 也可以把线程看成是一个轻量级的进程
③CPU如何处理任务
- 在单位时间时间片上只能执行一个线程
- CPU看到内存中有很多的线程,CPU在单位时间片(时间片:很微小的时间单位)上高速切换线程执行
3.cpu处理的最小单位是线程
④多线程下载软件为什么快
- CPU处理任务最小单位是线程,CPU是通过资源分配的方式,在多个线程之间,以时间片(时间片:很微小的时间单位)为单位,高速切换内存中要执行的线程任务。
- 在同一个时间片上,只能处理一个线程
- 在CPU的眼中,只看到内存中有很多线程,大家都是平等的,获取到CPU处理的机会是均等的,CPU会平均分配资源给每一个线程
- 自定义第一个线程
.①第一种线程的实现方式extends Thread
②注意事项
直接调用run方法和start的区别?
- 可以直接调用run方法,但是没有启动一个独立的线程;
- 只有调用start 才回启动一个独立的线程;
自己启动的线程和主线程有关系吗?
- 直接写一个最简单的hello word 程序,就有一个主线程
- 一个线程一旦启动就是独立的了,和创建启动它的环境没有直接的包含关系
4.多线程售票示例
5.实现创建启动线程方式二
第二种线程的实现方式implements Runnable
6. Thread类
1.线程休眠
线程类Thread当中有一个static void sleep(long millis)方法,在指定的毫秒数内让当前正在执行的线程休眠
①线程休眠作用
- 可以做倒计时
-
-
- 可以用来模拟网络延迟
-
-
2.线程的优先级
- 每个线程[线程对象]都有一个优先级,高优先级线程的执行优先于低优先级线程(简单说:如果一个线程的优先级越高,获得CPU资源的机会更大,不等于高优先级的就最先执行)
- int getPriority() 返回线程的优先级
- void setPriority(int newPriority) 更改线程的优先级
- 线程的默认优先级和创建它的环境线程的当前优先级一致,主线程的默认优先级是5
- 守护线程
- 守护线程(精灵线程/后台线程)
①每个线程都可以或不可以标记为一个守护程序
②后台线程仅仅就是对线程的一个分类或者标记
- 特点:
① 一般来说后台线程是为前台线程服务的(例如gc线程);
② 如果所有的前台线程都死了,那么后台线程也会自动的死亡;但是前台线程死了,后台线程不一定立即死亡(可能还需要收尸...)
③ 一个线程的默认状态和创建它的环境线程状态一致
5.等待线程终止join()
join为线程当中的方法,某线程实例调用该方法,其他线程会等待该线程执行完毕之后在执行
6线程礼让
线程之前相互客气一下
static void | yield() 暂停当前正在执行的线程对象,并执行其他线程。 |
第二题:什么是线程
①一个小的代码块,CPU独立处理的一个最小单位
②一个线程一个但启动之后,可以独立的获得CPU资源
③线程用来包装一个独立的功能
第三题:线程如何包装功能
①明确自己的要写的功能
②相当于以前,还是设计了一个普通的类[run方法线程主体--->根据功能来决定设计几个类]
第四题:实现启动线程的两种方式分别是什么?
- 明确要做的功能
- MyThread extends Thread
- 覆写run方法 写第一步中的功能
- MyThread mt = new MyThread();
- mt.start()
- 明确功能
- 自定义类my implements Runable
- 覆写run方法,写第一步中的功能
- My m = new My()
- My mt = new Thread(m);
- mt.start();
线程的基本语法2
- 线程同步
- 线程同步方式一:同步代码
- 语法结构
synchronized (同步监听对象) {
//可能引发线程安全问题的代码
}
- 特点:
- 必须保证多个线程访问的是同一个同步监听对象
- 同步监听对象,可以是任意的对象【必须保证1】
- this也是可以作为同步监听对象的【必须保证1】
- 一般常用的:当前类的字节码对象,作为同步监听对象
TicketThread.class:一个类对应的字节码对象只有一个
- 小结:多个线程,必须访问的是同一个同步监听对象
- 线程同步方式二:同步方法(不需要同步代码块了)
同步方法的效果:一旦方法被同步,一个线程访问未结束,另外一个线程不能访问。
- 就是在需要被同步的方法上面加关键字 synchronized
- 加的位置 :在返回值类型的前面
- 不需要也不能够显示的写同步监听对象
- 如果是一个非static的方法,那么同步监听对象就是this;
- 如果是static修饰的方法,那么同步监听对象就是当前方法所在的类的字节码对象
- 线程同步方式三:锁机制 Lock(接口)
语法:Lock l = new Lock(); //定义一把锁 ReentrantLock Lock = new ReentrantLock();
L.Lock(); //开启锁 Lock.Lock();
try{
//被锁保护的代码块
}finally{
Lock.unLock(); //释放锁
}
- 线程通信与等待唤醒
- 如何让两个线程交替执行?
- 如果当前线程是存款线程,判断银行账户中是否有钱,如果有钱,让当前线程等待,唤醒取款线程
- 如果当前线程是取款线程,判断银行账户中是有钱,如果没有前,让当前线程等待,唤醒存款线程
- 如何判断?
在银行账户类当中设置一个标识,boolean empty = true;当empty为ture表示银行没有钱
①存款线程判断如果为empty为ture,表示没有钱,则执行线程存款操作,存款结束之后,
设置当前正在执行的存款线程等待
修改标识empty=flase表示银行有钱了
唤醒取款线程
②取款线程判断如果为empty为false,表示有钱,则执行线程取款操作,取款结束之后,
设置当前正在执行的取款线程等待
修改标识empty=true表示银行有钱了
唤醒存款线程
- 如何让线程等待或者唤醒?
Object 其中有两个方法
- wait():如果一个线程调用了该方法,没有唤醒该线程它,它就一直等待
- notify():唤醒共享该对象的单个线程,可能是任意的一个。
- 线程的生命周期
- 线程的声明周期分几个阶段:
① 创建: 例如 Thread t = new Thread();
② 就绪: 调用了start方法 t.start() ---> 告诉CPU我准备好了
③ 运行: 获得CPU的资源,开始执行线程体中的代码
④ 死亡: 有多种情况导致死亡
- 例如线程体执行完毕(自然老死);
- 非自然死亡(异常没有处理好);
- 对象失去引用
- 对象被垃圾回收机制销毁
- 注意点:
① 休眠等操作可能导致正在运行的线程阻塞],阻塞完了(sleep完了)进入的是就绪状态
相互一一直等待,出现死锁!
② 一个线程死了就死了,不能够死而复生
- 定时器
- 什么是定时器?
java.util.TimerTask由 Timer 安排为一次执行或重复执行的任务
- Java中是的实现方式 java.util.Timer
Timer类常用方法:
void | schedule(TimerTask task, long delay) 安排在指定延迟后执行指定的任务 |