首页 > 代码库 > 多线程Thread
多线程Thread
多线程
一、程序、进程、线程的概念
①.程序(program)是为完成特定任务、用某种语言编写的一组指令的集合。即指一段静态的代码,静态对象。
②.进程(process)是程序的一次执行过程,或是正在运行的一个程序。动态过程:有它自身的产生、存在和消亡的过程。
程序是静态的,进程是动态的
③.线程(thread),进程可进一步细化为线程,是一个程序内部的一条执行路径。若一个程序可同一时间执行多个线程,就是支持多线程的
二、Java中多线程的创建和使用
①.Java语言的JVM允许程序运行多个线程,它通过java.lang.Thread类来实现。
Thread类的特性
每个线程都是通过某个特定Thread对象的run()方法来完成操作的,经常把run()方法的主体称为线程体
通过该Thread对象的start()方法来调用这个线程
构造方法
Thread():创建新的Thread对象
Thread(String threadname):创建线程并指定线程实例名
Thread(Runnable target):指定创建线程的目标对象,它实现了Runnable接口中的run方法
Thread(Runnable target, String name):创建新的Thread对象
②.创建线程的两种方式
1>继承Thread类
1) 定义子类继承Thread类。
2) 子类中重写Thread类中的run方法。
3) 创建Thread子类对象,即创建了线程对象。
4) 调用线程对象start方法:启动线程,调用run方法
2>实现Runnable接口
1)定义子类,实现Runnable接口。
2)子类中重写Runnable接口中的run方法。
3)通过Thread类含参构造器创建线程对象。
4)将Runnable接口的子类对象作为实际参数传递给Thread类的构造方法中。
5)调用Thread类的start方法:开启线程,调用Runnable子类接口的run方法。
③.继承方式和实现方式的联系与区别
1>联系
public class Thread extends Object implements Runnable
2>区别
继承Thread: 线程代码存放Thread子类run方法中。
实现Runnable:线程代码存在接口的子类的run方法。
3>实现方式的好处
1)避免了单继承的局限性
2)多个线程可以共享同一个接口实现类的对象,非常适合多个相同线程来处理同一份资源。
④.Thread的常用方法:
1.start():启动线程并执行相应的run()方法
2.run():子线程要执行的代码放入run()方法中
3.currentThread():静态的,调取当前的线程
4.getName():获取此线程的名字
5.setName():设置此线程的名字
6.yield():调用此方法的线程释放当前CPU的执行权
7.join():在A线程中调用B线程的join()方法,表示:当执行到此方法,A线程停止执行,直至B线程执行完毕,A线程再接着join()之后的代码执行
8.isAlive():判断当前线程是否还存活
9.sleep(long second):显式的让当前线程睡眠second毫秒
10.线程通信:wait() notify() notifyAll()
设置线程的优先级(线程的优先级越高,并不是一定会被优先指行,只是被优先执行的概率更大)
11.getPriority() :返回线程优先值
12.setPriority(int newPriority) :改变线程的优先级
三、线程的生命周期
新建: 当一个Thread类或其子类的对象被声明并创建时,新生的线程对象处于新建状态
就绪:处于新建状态的线程被start()后,将进入线程队列等待CPU时间片,此时它已具备了运行的条件
运行:当就绪的线程被调度并获得处理器资源时,便进入运行状态, run()方法定义了线程的操作和功能
阻塞:在某种特殊情况下,被人为挂起或执行输入输出操作时,让出 CPU 并临时中止自己的执行,进入阻塞状态
死亡:线程完成了它的全部工作或线程被提前强制性地中止
四、线程的安全问题
1.线程安全问题存在的原因?
由于一个线程在操作共享数据过程中,未执行完毕的情况下,另外的线程参与进来,导致共享数据存在了安全问题。
2.如何来解决线程的安全问题?
必须让一个线程操作共享数据完毕以后,其它线程才有机会参与共享数据的操作。
3.java如何实现线程的安全:线程的同步机制
方式一:同步代码块
synchronized(同步监视器){
//需要被同步的代码块(即为操作共享数据的代码)
}
1.共享数据:多个线程共同操作的同一个数据(变量)
2.同步监视器:由任何共享的一个类的对象来充当。哪个线程获取此监视器,谁就执行大括号里被同步的代码。俗称:锁
要求:所有的线程必须共用同一把锁!
注:在实现的方式中,考虑同步的话,可以使用this来充当锁。但是在继承的方式中,慎用this!
方式二:同步方法(此处默认同步监视器(锁)为this)
public synchronized void show (String name){
….
}
将操作共享数据的方法声明为synchronized。即此方法为同步方法,能够保证当其中一个线程执行
此方法时,其它线程在外等待直至此线程执行完此方法。
>同步方法的锁:this
4.线程的同步的弊端:由于同一个时间只能有一个线程访问共享数据,效率变低了。
五、互斥锁
在Java语言中,引入了对象互斥锁的概念,来保证共享数据操作的完整性。
每个对象都对应于一个可称为“互斥锁”的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。
关键字synchronized 来与对象的互斥锁联系。当某个对象用synchronized修饰时,表明该对象在任一时刻只能由一个线程访问。
同步的局限性:导致程序的执行效率要降低
同步方法(非静态的)的锁为this。
同步方法(静态的)的锁为当前类本身。
六、释放锁的操作
当前线程的同步方法、同步代码块执行结束
当前线程在同步代码块、同步方法中遇到break、return终止了该代码块、该方法的继续执行。
当前线程在同步代码块、同步方法中出现了未处理的Error或Exception,导致异常结束
当前线程在同步代码块、同步方法中执行了线程对象的wait()方法,当前线程暂停,并释放锁。
七、不会释放锁的操作
线程执行同步代码块或同步方法时,程序调用Thread.sleep()、Thread.yield()方法暂停当前线程的执行
线程执行同步代码块时,其他线程调用了该线程的suspend()方法将该线程挂起,该线程不会释放锁(同步监视器)。
应尽量避免使用suspend()和resume()来控制线程
八、线程的死锁问题
死锁:不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就形成了线程的死锁
解决方法①.专门的算法、原则②.尽量减少同步资源的定义
九、线程通信
①wait() 与 notify() 和 notifyAll()
wait():令当前线程挂起并放弃CPU、同步资源,使别的线程可访问并修改共享资源,而当前线程排队等候再次对资源的访问
在当前线程中调用方法: 对象名.wait()
使当前线程进入等待(某对象)状态 ,直到另一线程对该对象发出 notify (或notifyAll) 为止。
调用方法的必要条件:当前线程必须具有对该对象的监控权(加锁)
调用此方法后,当前线程将释放对象监控权 ,然后进入等待
在当前线程被notify后,要重新获得监控权,然后从断点处继续代码的执行。
notify():唤醒正在排队等待同步资源的线程中优先级最高者结束等待
notifyAll ():唤醒正在排队等待资源的所有线程结束等待.
在当前线程中调用方法: 对象名.notify()
功能:唤醒等待该对象监控权的一个线程。
调用方法的必要条件:当前线程必须具有对该对象的监控权(加锁)
②Java.lang.Object提供的这三个方法只有在synchronized方法或synchronized代码块中才能使用,否则会报java.lang.IllegalMonitorStateException异常
多线程Thread