多线程(知识点):
Run () | 重写Thread类的run()方法 |
Start () | 开启线程 |
currentThread () | 得到当前线程的实例对象 |
setDaemon (true) | 将线程设置为后台程序 |
setPriority (int newPriority) | 设置线程的优先级 |
Sleep (long millis) | 线程休眠millis秒 |
Yield () | 线程让步 |
Join () | 线程插队 |
Synchronized | 同步方法或代码块 |
Wait() | 使当前线程放弃同步锁并进入等待,直到其他线程进入此同步锁,并调用notify()方法,或notifyAll()方法唤醒该线程为止。 |
Notify () | 唤醒此同步锁上等待的第一个调用wait()方法的线程。 |
notifyALL () | 唤醒此同步锁上调用wait()方法的所有线程 |
多线程:并发执行 | 指一个应用程序中有多条并发执行的线索,每条线索都被称作一个线程,它们会交替执行,彼此间可以进行通信。 |
线程概述:
进程: | 在一个操作系统中,每个独立执行的程序都可称为一个进程,也就是“正在运行的程序”。 |
线程: | 在一个程序中还可以有多个执行单元同时运行,这些执行单元可以看作程序执行的一条条线索,被称为线程。 |
线程的创建:
继承Thread类创建多线程: | 通过继承Thread类,并重写Thread类中的run方法便可实现多线程。在Thread类中,提供了一个start()方法用于启动新线程。
| |||||||||||||
实现Runnable: | 为了一个类继承了某个父类就无法再继承Thread类,Thread类提供了另一个构造方法Thread(Runnable targer),其中Runnable是一个接口,它只有一个run()方法。当通过Thread(Runnable targer)构造方法创建线程对象时,只需为该方法传递一个实现了Runnable接口的实例对象,这样就不需要调用Thread类中的run()方法。
| |||||||||||||
同种实现多线程方式的对比分析: |
通过上面的两个例程可以看出,实现Runnable接口相对于继承Thread类来说,有如下显著的好处:
| |||||||||||||
后台线程: | 如果某个线程对象在启动之前调用了setDaemon(true)语句,这个线程就变成一个后台线程。
注意:要将某个线程设置为后台线程,必须在该线程启动之前,也就是说setDaemon()方法必须在start()方法之前调用 ,否则会引发IllegalThreadStateException异常 | |||||||||||||
线程的生命周期及状态转换: | 新建状态——就绪状态——阻塞状态——运行状态——死亡状态
| |||||||||||||
线程的调度: | Java虚拟机执照特定的机制为程序中的每个线程分配CPU的使用权,这种机制被称作线程的调度。
Java虚拟机默认采用抢占式调度模型。 线程的调度 如果要对线程进行调度,最直接的方式就是设置线程的优先级。优先级越高的线程获得CPU执行的机会越大。越小机会则越小。 Thread类的优先级常量
通过Thread类的setPriority(int new Priority)方法对其进行设置,该方法中的参数newPriority接收的是1~10之间的整数或者Thread类的三个静态常量
线程休眠 如果希望人为地控制线程,使正在执行的线程暂停,将CPU让给别的线程,这时可以使用静态方法sleep(long millis),该方法可以让当前正在执行的线程暂停一段时间,进入休眠等待状态。当前线程调用sleep(long millis)方法后,在指定时间(参数 millis)内是不会执行的。这样其它线程就可以得到执行的机会了。
注意:sleep()是静态方法,只能控制当前正在运行的线程休眠,而不能控制其他线程休眠。 线程让步 线程让步可以通过yield()方法来实现,该方法和sleep()方法有点相似,都可以让当前正在运行的线程暂停,区别在于yield()方法不会阻塞该线程,它只是将线程转换成就绪状态,让系统的调度器重新调度一次。当某个线程调用yield()方法之后,只有与当前线程优先级相同或者更高的线程才能获得执行的机会。
线程插队: 当在某个线程中调用其它线程的join()方法时,调用的线程将被阻塞,直到被join()方法加入的线程执行完成后才会继续运行.
| |||||||||||||
多线程同步: | 线程安全: 当多个线程去访问同一个资源时,会引发一些安全问题.为了解决这样的问题,需要实现多线程的同步,即限制某个资源在同一时刻只能被一个线程访问.
在售票程序的while循环中添加了sleep()方法,导致结果出现了负号。要想解决这个问题请看下面同步代码块 同步代码块: 了解到线程安全问题其实就是由多个线程同时处理共享资源所导致的。要想解决上例线程的安全问题,必须得保证下面用于处理共享资源代码 在任何时刻只能有一个线程访问 当多个线程使用同一个共享资源时,可以将处理共享资源的代码放置在一个代码块中,使用synchronized关键字来修饰,被称作同步代码块
注意:线程在获得锁对象时有一定的随机性。 同步代码块中的锁对象可以是任意类型的对象,但多个线程共享的锁对象必须是唯一的。“任意”说的是共享锁对象的类型。所以,锁对象的创建代码不能放到run方法中,否则每个线程运行到run()方法都会创建一个新对象,这样每个线程都会有一个不同的锁,每个锁都有自己的标志位。线程之间便不能产生同步的效果。 同步方法: 当把共享资源的操作放在synchronized定义的区域内时,便为这些操作加了同步锁。在方法前面同样可以使用synchronzed关键字来修饰,被修饰的方法为同步方法,它能实现和同步代码块同样的功能。
被synchronized修饰的方法在某一时刻只允许一个线程访问,访问该方法的其他线程都会发生阻塞,直到当前线程访问完毕后,其他线程才有机会执行方法。
死锁问题: 两个线程在运行时都在等待对方的锁,这样便造成了程序的停滞,这种现象称为死锁。
| |||||||||||||
多线程通信: | 在多线程的程序中,上下工序可以看作两个线程,这两个线程之间需要协同完成工作,就需要线程之间进行通信。
运行出现取出的数据不是连续,出现断层! 解决上面问题 需要控制多个线程按照一定的顺序轮流执行,此时需要让线程间进行通信 唤醒线程的方法:
注意:由于Java中所有类都是Object类的子类或间接子类,因此任何类的实例对象都可以直接使用这些方法。
|