线程
线程:
**线程中内容若出现你所不能接受都是现实,都是对的,现在的电脑都多核CPU**
进程和线程:
进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内幕才能空间
例子:windows下一个运行的eclipse.exe就是一个进行
那么我们此时就可以同时处理多个进程cpu自己完成
进程是需要多个线程进行支持(一个进程可以有多个线程)
使用线程这个技术来达到目的
public class A{
public static void main(String[] args){
play();
yinyue();
}
public static void play(){
循环50次 玩游戏
}
public static void yinyue(){
循环50次 听歌
}
}
线程是指在进程中一个执行任务的单元,一个进程中可以同时并发运行多个线程
例如:迅雷中同时下载多个[学习视频.avi]
一个进程最少有一个线程,那么为了提高效率,可以在一个进程中开启多个线程执行任务,即多线程
进程和线程的区别
进程:有独立的内存空间,进程中的数据是存放在(堆或栈空间中),至少有一个线程支持
线程:堆空间是共享的,栈空间是独立的,线程消耗的资源也比进程要小很多,线程之间是可以相互影响
又称为轻型进程
线程的多并发运行,从微观的角度而言所有的执行都是有先后顺序,那么那个线程执行完取决于CPU的调度
java程序时(JVM来调度的 --> CPU),程序猿是控制不了CPU的,但是我们可以通过某些方式来进行线程的干预操作
并发和并行:
并发和并行有相识之处
并行: 指两个或多个事件在同一个时刻点上发生
并发: 指两个或多个事件在同一段时间内发生
在操作系统中,在多道程序环境下,并发性是指在一段时间内宏观上有多个程序在同时运行,但在单CPU系统中,每一时刻却仅能有一道程序执行(时间片),故微观上这些程序只能是分时地交替执行。
倘若计算机系统中有多个CPU,则这些可以并发执行的程序便可被分配到多个处理器上,实现多任务并行执行,即利用每个处理器来处理一个可并发执行的程序,这样,多个程序便可以同时执行,因为是微观的,所以大家在使用电脑的时候感觉就是多个程序是同时执行的。
所以,大家买电脑的时候喜欢买“核”多的,其原因就是“多核处理器”电脑可以同时并行地处理多个程序,从而提高了电脑的运行效率。
单核处理器的计算机肯定是不能并行的处理多个任务的,只能是多个任务在单个CPU上并发运行。
同理,线程也是一样的,从宏观角度上理解线程是并行运行的,但是从微观角度上分析却是串行运行的,即一个线程一个线程的去运行,当系统只有一个CPU时,线程会以某种顺序执行多个线程,我们把这种情况称之为线程调度。
时间片即CPU分配给各个程序的运行时间(很小的概念).
多线程优势:
多线程作为一种多任务、并发的工作方式,当然有其存在优势:
① 进程之前不能共享内存,而线程之间共享内存(堆内存)则很简单。
② 系统创建进程时需要为该进程重新分配系统资源,创建线程则代价小很多,因此实现多任务并发时,多线程效率更高.
③ Java语言本身内置多线程功能的支持,而不是单纯第作为底层系统的调度方式,从而简化了多线程编程.
在程序中如何开启线程
创建线程有两个方式
继承Thread类
实现接口Runnable
只要实现一种方式即可
-----------------------------------------------------------------
若使用继承的方式来创建线程
创建一个类继承于Thread这个类创建线程,此时这个子类称为线程类
只要是继承Thread类就必须重写run方法,这有这样才能达到开启线程的目录
步骤:
1.定义一个类A继承于Thread类
2.在A中写Thread类中的run方法并将线程中更需要执行的逻辑写入到这个方法中
3在main方法中创建线程对象,并启动线程
子类 对象名 = new 子类()
开启线程
对象.start();
ps:千万不要调用run方法,不然就相当于执行了run方法而不是开启线程
看Thread包
--------------------------------------------------------------------------
实现Runnable接口
步骤:
1.定义一个A类 实现 Runnable接口
2.在A中重写Runnable接口中的run方法,并将线程逻辑写入到run方法
3.在main 方法创建线程对象,并开启线程
Thread 对象名 = new Thread(传入实现了Runnable接口实现类的对象);
开启线程
对象名.start();
看Runnable包
继承Thread和实现Runnable接口的特点
继承Thread还是实现Runnable接口都可以达到实现线程类的目的
在实际开发中建议使用实现Runnable接口的方式来实现线程
java是单一继承一个类只能有一个直接父类,所以类的可扩展性就大大的降低了
但是可以实现多个接口,既然可以实现多可接口,此时就建议使用Runnable接口的形式来完成
匿名内部类的形式实现线程
在不需要创建一个类并且只实现一次线程的情况下,强烈推荐内名内部类形式
看AnonymityThread包
线程中常用的方法:
Thread.state --> 获取线程状态
线程状态。线程可以处于下列状态之一:
NEW(出生)
至今尚未启动的线程处于这种状态。
RUNNABLE(准备就绪和执行)
正在 Java 虚拟机中执行的线程处于这种状态。
BLOCKED(睡眠)
受阻塞并等待某个监视器锁的线程处于这种状态。
WAITING(等待) --> 生产者和消费者模式-->线程交替执行
无限期地等待另一个线程来执行某一特定操作的线程处于这种状态。
TIMED_WAITING(时间等待)
等待另一个线程来执行取决于指定等待时间的操作的线程处于这种状态。
TERMINATED(消亡)
已退出的线程处于这种状态。
需求:查看线程状态
通过代码看到了线程的状态
获取线程的状态调用 --> getState() -->成员方法--> 线程对象调用
获取当前线程的名字 --> getName() --> 成员方法 --> 线程对象调用
修改当前线程的名字 --> setName() -->参数 要修改的名字String类型 --> 线程对象调用
ps:在没有修改线程名之前,线程名的组成
Thread + "-" + 数字 ----> 数字会随着线程对象的创建而逐渐增加 递增+1 默认第一个是0
如何设置线程优先级
优先级:线程的执行时取决于CPU时间片的
修改线程优先级可以提高线程获取CPU时间片的机率
优先级的设置只能达到告诉CPU可以优先考虑给予时间片,但实际CPU是否给予,完全取决于CPU
线程优先级组成 1~10 组成
1代表最低 10代表最高 默认创建的线程优先级是5
API中提供了三个静态字段
static int MAX_PRIORITY ---> 10
线程可以具有的最高优先级。
static int MIN_PRIORITY ---> 1
线程可以具有的最低优先级。
static int NORM_PRIORITY ---> 5
分配给线程的默认优先级
void setPriority(int newPriority) 更改线程的优先级。
需求: 设置优先级
看Priority包
如何修改线程的名字
在没有修改线程名字之前Thread-0 0是自增的
1.通过线程对象.setName(线程名)
2.实现Runnable接口,在创建Thread对象时调用两个参数的构造方法
Thread td = new Thread(实现Runnable接口的实现类对象,线程名)
3.创建一个类继承于Thread类
class A extends Thread{
//提供一个构造方法 有参的 设置名字
public A(String name){
super(name);
}
@Override
public void run(){
实现线程逻辑
}
public static void main(String[] args){
Thread td = new A("线程的名字1");
System.out.println(td.getName());
}
}
线程休眠
静态方法 Sleep-->参数 毫秒值 设置多少毫秒 当前线程就睡眠多少毫秒
一旦睡眠会让出CPU时间片,此时其他线程就可以再次获取到时间片
一旦睡眠完成(醒了)此时当前线程会回到就绪状态,和其他线程继续争取CPU时间
需求:创建一个线程 ,在主线程中执行,在主线程中创建一个循环 i == 20的时候 启动子线程, 主线程要睡眠
看Sleep包
ps:sleep方法在线程同步锁/同步监听情况下是不能释放cpu时间片
起到一个效果,做到延迟(延迟多少毫秒在执行)
线程礼让(了解)
这是一个十分不明显的方法
yield(),若在线程中触发这个方法,此时当前线程会对CPU发送一个暗示"不急着运行",
本线程所占用的CPU时间片就会被回收,分配给其他线程
至于是否被CPU立即回,完全取决于CPU,即可以回收也可以不回收,而且CPU会自动的忽略这个信息
需求:模拟两个乘客老人,年轻人.都做公交 做100站,老人随机上车,让座
看Yield包
线程合并
当一个线程正在处于运行中,可以让当前线程中将入另外一个线程,只有等待假如现车执行完毕,然后当前线程才会执行
Join(合并)
特点:
1.线程合并,当前线程一定会释放CPU时间,CPU时间片会分给Join的线程
2.那个线程需要合并就在当前线程中添加要合并的线程对象
3.Join之前一定要将线程处于准备装填Start
需求:咱们妹子再看电视{精钢葫芦娃大战七个小矮人},当妹子看到第10集
男生,就要看喜洋洋和灰太狼(10),妹子才能看下去
例子:异步请求
线程终止(中断线程)
1.若需要线程停止千万不要使用Stop()
2.替代Stop方法
提供一个方法这个方法可以中断线程
void interrupt() 不能中断线程
可以给线程一个中断标记
static boolean interrupted() 检查中断标记
线程中有中断 此时返回true 没有中断标记是false
才能让线程停止 ---> 线程停止其实就是在做 return 结束一个方法
不建议直接在run 方法中添加return ,这样做的话就相当于结束了方法,而不是让线程停止
让线程停止,中断标记和中断标记检测方法一起使用,若检查标记存储,此时在停止线程--> return
需求:创建一个线程对象 启动线程,停止
扩展:sleep方法的时候 -->异常 中断异常 InterruptedException
sleep可以通过中断标记来达到提前让线程苏醒
通过中断标记来打断Sleep睡眠
看Interrupt包
多线程并发访问临界资源问题
需求: 十一,火车站卖票只有100张 4个窗口同时售卖,将这100张票
ps:1.有且仅有100张票 --> 400张
2.有序输出100--99---98 --> 不能出现重票
3.不准出现 0票或是负数
锁 --> 共享资源 --> 线程锁
线程锁 --> 对象锁 类锁
生产者和消费者模式 --> 线程交替执行
ps: JDK1.5新锁
死锁(了解)
单利多线程并发访问安全问题
线程的声明周期图
TCP --> 基本概念
TCP/UDP/反射