线程概述
进程:计算机中特定功能的程序在数据集上的一次运行。
线程:线程是进程的一个单元。
多线程:一个进程中有多个线程在同时运行。如迅雷下载,迅雷软件的一次运行就是一个进程,在迅雷中可以同时下载多个电影,这就是多线程(每一个下载都是一个线程)。
Jvm是多线程的,在我们运行jvm的时候后台会运行垃圾回收的线程,来清理没有被引用的对象。
线程的实现
1.线程实现的第一种方式
创建新执行线程有两种方法。一种方法是将类声明为Thread的子类,该子类应重写Thread类的run方法,接下来可以分配并启动该子类的实例。
线程启动的时候使用线程的start()方法,而不是run()
2.线程实现的第二种方式
创建线程的另一种方法是声明实现Runnable接口的类,该类然后实现run方法,然后可以分配该类的实例,在创建Thread时作为一个参数来传递并启动。
3.线程的执行原理
线程的并发执行通过多个线程不断的切换CPU的资源,这个速度非常快,我们感知不到,我们能感知到的就是三个线程在并发的执行。
4.线程的生命周期
(1)新建状态:线程被new出来
(2)准备就绪:线程具有执行的资格,即线程调用了start(),没有执行权力。
(3)运行:具备执行的资格和具备执行的权利。
(4)阻塞(挂起):没有执行资格和执行权利。
(5)销毁:线程的对象变成垃圾,释放资源。
5.线程并发安全
互联网的项目中存在着大量的并发的案例,如:买火车票,电商网站(秒杀货物)。
范例:火车站有一百张票,四个窗口同时买票。
分析:四个窗口是4个线程,同时在运行,一百张票是4个线程的共享资源。
采用第一种方式Thread
并发安全范例:
上厕所排队(锁门)
6.解决方案:
针对线程的安全性问题,我们需要使用同步(就是要加锁,共享资源只能同时一个人在访问)锁
语法:
synchronized(锁对象(一把钥匙)){
// 操作共享资源的代码
}
同步代码加在什么地方呢?
判断标准:
1.代码被多个线程访问。
2.代码中有共享的数据。
3.共享的数据被多条语句操作。
synchronized同步代码块的锁对象可以是任意类对象(线程的实现方式使用时继承与Thread),这个对象必须是线程共享的(静态的)
范例:
synchronized是可以加在方法上,如果是静态方法Synchronized的锁对象就是类的类对象,如果不是静态的方法。synchronized如果加在对象方法上,那么他的锁是this.
线程的休眠:
线程的休眠是很必要的,因为在做服务器端的时候,为了减少服务器的压力,我们需要休眠。
如果休眠是在同步代码块中执行,休眠不会让出锁对象。
7.线程间的通信
生产者和消费者
生产者生成水果,如果水果没有被买走那么就不生产,处于等待被买走状态。如果被消费者买走的时候消费者会告诉生产者我已经把水果买走了请你生产。消费者,同理,如果水果已经生产出来了就直接买走,买走之后就通知生产者,水果已经没了,请生产。
注意:
1.线程间的通信共享数据一定要有同步代码块synchronized
2.一定要有wait和notify,而且二者一定是成对出现。
3.生产者和消费者的线程实现一定是在while(true)中
实例:
生产者:
消费者:
实体对象:
实现:
8.线程的优先级
我们可以通过public final void setPriority(int newPriority)来设置线程的优先级,但是优先级并不是绝对的,只是相对来说比其他线程得到的cpu的资源机会多一些。
示例代码:
9.加入线程和等待线程
join线程会抢先拿到CPU来执行线程,然后其他的后执行
10.等待线程
yield:暂停当前正在执行的线程对象,并执行其他线程
当前线程从运行阶段回到就绪阶段,目的是把CPU的资源让给其他的线程
11.守护线程
setDaemon将该线程标记为守护线程或用户线程
守护线程会随着主线程结束而结束
12.线程死锁
代码示例:
注意:在线程开发当中要避免出现死锁,否则程序会一直挂死在那。
’