多线程.docx
- 文档编号:5942801
- 上传时间:2023-01-02
- 格式:DOCX
- 页数:9
- 大小:171.68KB
多线程.docx
《多线程.docx》由会员分享,可在线阅读,更多相关《多线程.docx(9页珍藏版)》请在冰豆网上搜索。
多线程
1.多线程
1)引入
大部分时间我们都是单线程编程。
程序只有一条执行流。
如果我们需要开发一个服务器程序,这个服务器需要向不同的客户端提供服务。
不同客户端之间互不干扰。
多线程程序可以有多个执行流,这些执行流之间互不干扰。
2)线程
进程(Process):
操作系统都支持同时运行多个任务,一个任务通常就是一个程序,每个运行中的程序叫进程。
一个进程在运行时可能有多个执行流,即线程。
进程的特征:
A,独立性
B,动态性
C,并发性
线程(Thread)
也称为轻量级进程,是进程的执行单元。
线程在进程中也是独立的。
当进程被初始化以后,主线程就被创建了。
线程调度策略:
A,分时策略
B,抢占式策略
(os采用的就是B)
为什么要使用多线程呢?
当操作系统创建一个进程时,就必须为该进程分配独立的内存空间,并分配一些其它资源,但创建一个线程比较简单,因为使用多线程实现并发比使用多进程性能要高得多。
2.java中线程的创建和启动
1)继承Thread类
java中可以写一个类继承Thread类来创建线程类。
该子类应重写Thread类的run方法。
所有的线程对象都必须是Thread类的对象或子类的对象。
每个线程的作用就是完成一定的任务(即执行一段程序)。
java中使用run()方法来封装这段程序,这段程序被称为线程执行体。
步骤:
A,定义一个Thread的子类,重写run方法
B,创建这个类的对象
C,调用start()方法-启动(切记不能直接调用run方法)
示例:
FirstThread示例结论:
线程调度具有随机性。
结果是不确定的。
示例:
SecondThread示例结论:
如果把i变量看成是电影票,结果中可能发生重票的现象,所以这是线程不安全的。
2)实现Runnable接口
步骤:
A,定义一个Runnable接口的实现类,重写run()方法
B,创建A中类的对象,并将这个对象作为参数传递给Thread的构造方法。
这个Thread对象才是正的线程对象。
A中创建的Runnable对象仅作为Thread对象的target。
其中的run()方法作为线程的执行体。
实际的线程对象仍然是thread的实例,这个实例负责调用其target中的run方法。
示例ThreeThread的结论:
因为三个线程实例共用一个target。
因此得到的i是连续的,说明三个线程实例共享一个i变量。
注意事项:
A,共享变量不用声明成静态的。
B,通常只需创建一个target,由多个线程共享。
真实开发中,我们通常用第二种.
3)线程的生命周期
线程被创建后调用start方法启动以后,不是马上就时入执行状态。
仅仅具有可执行资格而已。
线程的五种状态:
A,新建(New)
B,就绪(Runnable)
C,执行(Running)
D,阻塞(Blocked)
E,死亡(Dead)
新建:
只是分配了内存空间,初始了成员变量
就绪:
表示该线程具有可执行能力。
运行:
就入就绪状态的线程获得CPU资源,开始执行run。
一旦时间片到期,CPU会剥夺其所占用的资源,其他线程获得机会。
阻塞:
当线程调用了其sleep方法时,就进入了阻塞状态,其他线程就获得机会了。
被阻塞的线程阻塞解除后直接进入就绪状态。
死亡:
run方法执行完,或程序中有异常中断。
4)线程加入
join()
这是让一个线程等待另一个线程的方法。
调用join方法的线程执行完毕其他线程才能继续。
线程对象必须启动(即就绪状态)后才能调用join()方法,否则根本无法获得cpu资源。
5)后台线程(守护线程,精灵线程)
setDaemon(true);
设置动作要在start()之前。
GC是典型的后台线程。
它的任务是为其他线程提供服务的。
特征:
如果所有的前台线程都死亡,后台线程自动死亡。
注意:
前台线程结束后,尽管后台线程还没执行完,但收到前台线程死亡通知需要时间,从后台线程接受指令到作出响应需要时间,这个时间可能会让后台线程再执行一阵子。
6)线程休眠
sleep(longtime)-毫秒
让当前正在执行的线程暂停,进入到阻塞状态。
当time时间内,这个线程不会获得执行机会,即使系统中没有可运行的其他线程,这个线程也不会执行,可以用来控制程序暂停。
7)线程让步
yield()
暂停当前正在执行的线程对象,并执行其他线程。
可以让当前正在执行的线程暂停,但并不阻塞,将这个线程直接转入就绪状态。
只是让当前线程暂停,让调度器重新调度一次。
8)线程优先级
优先级高只表明线程可以得到较多的执行机会。
但不保证一定优先执行。
9)线程安全问题
A,是多线程环境
B,有共享数据
C,有多条语句修改共享数据
经典的线程安全问题:
银行取钱问题(余额出现负值)
解决方法:
同步操作
A,同步代码块
synchronized(account){
同步代码;
}
account这个对象被称为同步监视器
同步代码块被称为临界区。
任何时刻临界区内只能有一个线程。
或者说任何时刻只能有一个线程可以获得同步监视器的锁定。
同步代码块执行结束,该线程自然释放对这个同步监视器的锁定。
将有可能引发安全的问题的代码写到同步代码块中,同时为这个代码块加锁(对象),这个对象必须是所有线程对象共享的数据对象。
(要么是所有线程都操作的对象,或者是一个不相关的静态属性对象)
完整代码:
B,同步方法
同步方法不需要显式指定同步监视器,同步方法的同步监视器就是this
即当前对象本身。
C,加锁
JDK5以后才提供可参考API示例代码
ReentrantLock
lock()
unlock()
生产者消费者:
Account
DrawThread
DepositThread
在Accont中设置一个标记,用来表示是否还有钱。
当flag为false时,表示没有存款,存款线程可以继续执行,取款线程等待。
当存款以后,将flag设置为true,并调用notifyAll()唤醒其他线程。
当flag为true时,表示有存款,取款线程可以继续执行,存款线程等待。
3.线程池
系统启动一个新线程的成本较高。
线程池在系统启动会创建一些空闲的线程,程序将一个Runnable对象传给线程池,线程池会启动一个线程来执行其run方法。
当run方法执行结束,线程不会死亡,会再次回到线程池变成空闲状态。
java从JDK5开始支持内建线程池。
Executors工厂类来生产线程池对象。
submit(Runnabler)
shutdown()
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 多线程