程序与进程
程序:一段静态的代码。
进程:程序的一次动态执行过程,它对应从代码加载、执行到执行完毕的一个完整过程。
进程也称任务,支持多个进程同时执行的OS就被称为多进程OS或多任务OS
进程与线程
在一个程序内部也可以实现多个任务并发执行,其中每个任务称为线程。
线程是比进程更小的执行单位,它是在一个进程中独立的控制流,即程序内部的控制流。
特点:线程不能独立运行,必须依赖于进程,在进程中运行。
每个程序至少有一个线程称为主线程。
单线程:只有一条线程的进程称为单线程
多线程:有不止一个线程的进程称为多线程
开启多线程的优点和缺点
提高界面程序响应速度。通过使用线程,可以将需要大量时间完成的流程在后台启动单独的线程完成,提高前台界面的相应速度。
充分利用系统资源,提高效率。通过在一个程序内部同时执行多个流程,可以充分利用CPU等系统资源,从而最大限度的发挥硬件的性能。
当程序中的线程数量比较多时,系统将花费大量的时间进行线程的切换,这反而会降低程序的执行效率。但是,相对于优势来说,劣势还是很有限的,所以现在的项目开发中,多线程编程技术得到了广泛的应用。
多线程的实现方式
在实际实现线程时,Java语言提供了三种实现方式:
继承Thread类
实现Runnable接口
使用Timer和TimerTask组合
继承Thread类实现多线程。
MyThread tt1 = new MyThread ();
//启动线程
tt1.start();
try{
for(inti = 0;i < 5;i++){
//延时1秒
Thread.sleep(1000);
System.out.println("Main:"+ i);
}
}catch(Exceptione){}
注意:
线程的特性:随机性,系统在执行多线程程序时只保证线程是交替执行的,至于哪个线程先执行哪个线程后执行,则无法获得保证,需要书写专门的代码才可以保证执行的顺序。
对于同一个线程类,也可以启动多个线程。
Thread2 t2 = new Thread2(); t2.start();
Thread2 t3 = new Thread2(); t3.start();
同一个线程不能启动两次,例如
Thread2 t2 = new Thread2();
t2.start(); t2.start(); //错误
当自定义线程中的run方法执行完成以后,则自定义线程自然死亡。而对于系统线程来说,只有当main方法执行结束,而且启动的其它线程都结束以后,才会结束。当系统线程执行结束以后,程序的执行才真正结束。
实现Runable接口
多线程对象实现java.lang.Runnable接口并且在该类中重写Runnable接口的run方法。
好处:实现Runable接口的方法避免了单继承的局限性。
线程的生命周期
新建(start())——就绪(cpu可用)——运行——死亡
( 阻塞 )——死亡
线程的优先级
把线程从就绪状态进入运行状态的过程叫做线程调度。负责调度工作的机构叫做调度管理器。
优先级:线程的优先级的取值范围是1~10。
MAX_PRIORITY = 10
NORM_PRIORITY = 5
MIN_PRIORITY = 1
得到或修改线程的优先级
public final int getPriority();
public final void setPriority(int newPriority);
常用方法
void run() //创建该类的子类时必须实现的方法
void start() //开启线程的方法
static voidsleep(long t) //释放CPU的执行权,不释放锁
static voidsleep(long millis,int nanos)
final voidwait()//释放CPU的执行权,释放锁
final voidnotify()
static voidyied()//可以对当前线程进行临时暂停(让线程将资源释放出来)
public finalvoid stop()//结束线程,但由于安全的原因过时
为什么需要“线程同步”
线程间共享代码和数据可以节省系统开销,提高程序运行效率,但同时也导致了数据的“访问冲突”问题,如何实现线程间的有机交互、并确保共享资源在某些关键时段只能被一个线程访问,即所谓的“线程同步”(Synchronization)就变得至关重要。
临界资源
多个线程间共享的数据称为临界资源(Critical Resource),由于是线程调度器负责线程的调度,程序员无法精确控制多线程的交替顺序。因此,多线程对临界资源的访问有时会导致数据的不一致行。
互斥锁
每个对象都对应于一个可称为“互斥锁”的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。
Java对象默认是可以被多个线程共用的,只是在需要时才启动“互斥锁”机制,成为专用对象。
关键字synchronized用来与对象的互斥锁联系
当某个对象用synchronized修饰时,表明该对象已启动“互斥锁”机制,在任一时刻只能由一个线程访问,即使该线程出现堵塞,该对象的被锁定状态也不会解除,其他线程任不能访问该对象。
线程同步通信
为避免死锁,就应该让线程在进入阻塞状态时尽量释放其锁定的资源,以为其他的线程提供运行的机会,Object类中定义了几个有用的方法:wait()、notify()、notifyAll()。
wait():被锁定的对象可以调用wait()方法,这将导致当前线程被阻塞并释放该对象的互斥锁,即解除了wait()方法当前对象的锁定状态,其他的线程就有机会访问该对象。
notify():唤醒调用wait()方法后被阻塞的线程。每次运行该方法只能唤醒一个线程。
notifyAll():唤醒所有调用wait()方法被阻塞的线程。