线程

来源:互联网 发布:如何把域名卖出去 编辑:程序博客网 时间:2024/06/03 02:45

线程状态

在Java中,一个线程有4种状态,任何一个线程都处于这4种状态中的一种。

微笑创建状态(new):调用new方法产生一个线程对象后、调用start方法前所处的状态。线程对象虽然已经创建,但还没有调用start方法启动,因此无法执行。当线程处于创建状态时,线程对象可以调用start方法进入启动状态,也可以调用stop方法进入停止状态。

吐舌头可运行状态(runnable):当线程对象执行start方法后,线程就转入可运行状态。进入此状态只是说明线程对象具有了可运行的条件,但线程并不一定处于运行状态。因为在但处理器系统中运行多线程程序时,一个时间点只有一个线程运行,系统通过调度机制实现宏观意义上的运行线程共享处理器。因此一个线程是否在运行,除了线程必须处于runnable状态外,还取决于优先级和调度。

大笑不可运行状态(non runnable):线程处于不可运行状态是由于线程被挂起或者发生阻塞,例如对一个线程调用wait函数后,它就可能进入阻塞状态;调用线程的notify或notifyAll方法后它才能再次回到可执行状态。

鄙视退出状态(done):一个线程可以从任何一个状态中调用stop方法进入退出状态。线程一旦进入退出状态就不存在了,不能再返回到其他的状态。除此之外,如果线程执行完run方法,也会自动进入退出状态。

线程调度

多线程应用程序的每一个线程的重要性和优先级可能不同,例如有多个线程都在等待获得CPU的时间片,那么优先级高的线程就能抢占CPU并得以执行;当多个线程交替抢占CPU时,优先级高的线程占用的时间应该多。因此,高优先级的线程执行的效率会高些,执行速度也会快一些。

在Java中,CPU的使用通常是抢占式调度模式不需要时间片分配进程。抢占式调度模式是指许多线程同时处于可运行状态,但只有一个线程正在运行。当线程一直运行直到结束,或者进入不可运行状态,或者具有更高优先级的线程变为可运行状态,它将会让出CPU。线程设置优先级如下:

public final void setPriority( int newPriority )

设置线程的优先级为newPriority。newPriority的值必须在MIN_PRIORITY到MAX_PRIORITY范围内,通常它们的值分别是1和10。目前Windows系统只支持3个级别的优先级:Thread.MAX_PRIORITY、Thread.MIN_PRIORITY和Thread.NORM_PRIORITY 。

public final int getPriority()

获得当前线程的优先级。

线程同步

Java应用程序中的多线程可以共享资源,例如文件、数据库、内存等。当线程以并发模式访问共享数据时,共享数据可能会发生冲突。Java引入线程同步的概念,以实现共享数据的一致性。线程同步机制让多个线程有序的访问共享资源,而不是同时操作共享资源。

为了解决线程不同步而导致的错误,Java提供了“锁”机制。原理是每个线程进入共享代码之前获得锁,否则不能进入共享代码区,并且在退出共享代码之前释放该锁,这样就解决了多个线程竞争共享代码的情况,达到线程同步的目的。Java中锁机制的实现是在共享代码之前加入synchronized关键字。

在一个类中,用关键字 synchronized 声明的方法为同步方法。Java有一个专门负责管理线程对象中同步方法访问的工具——同步模型监视器,它的原理是为每个具有同步代码的对象准备唯一一把“锁”。当多个线程访问对象时,只有取得锁的线程才能进入同步方法,其他访问共享对象的线程停留在对象中等待,如果获得锁的线程调用wait方法放弃锁,那么其他等待获得锁的线程将有机会获得锁。当某一个等待线程取得锁,它将执行同步方法,而其他没有取得锁的线程仍然继续等待获得锁。

Java程序中线程之间通过消息实现相互通信,wait、notify以及notifyAll方法可完成线程间的消息传递。例如,一个对象包含一个synchronized同步方法,同一时刻只能有一个获得锁的线程访问该对象中的同步方法,其他线程被阻塞在对象中等待获得锁。当线程调用wait方法可使该进程进入阻塞状态,其他线程调用notify或notifyAll方法唤醒该线程。

class 类名{public synchronized 类型名 方法名称(){...}}


对于同步块,synchronized获取的是参数中的对象锁。

synchronized( obj ){...}

当线程执行到这里的同步块时,它必须获取obj这个对象的锁才能执行同步块;否则线程只能等待获得锁。必须注意的是obj对象的作用范围不同,控制情况不尽相同。示例如下:

public void method(){Object obj = new Object(); //创建局部Object类型对象objsynchronized( obj ){       //同步块...}}

上面的代码创建了一个局部对象obj 。由于每一个线程执行到 Object obj = new Object() 时都会产生一个obj对象,每一个线程都可以获得创建的新的obj对象的锁,不会相互影响,因此这段程序不会起到同步的作用。如果同步的是类的属性,情况就不同了。同步类的成员变量的一般格式如下:

class Method{Object obj = new Object();  //创建Object类型的成员变量objpublic void test(){synchronized( obj ){    //同步块 ...}}}

当两个并发线程访问同一个对象的synchronized( obj ) 同步代码块时,一段时间内只能有一个线程运行。另外的线程必须等到当前线程执行完同步代码块释放锁之后,获得锁的线程将执行同步代码块。有的可以通过下面的格式声明同步块。

public void method(){synchronized( this ){    //同步块...}}

当有一个线程访问某个对象的 synchronized(this)同步代码块时,另外一个线程必须等待该线程执行完此代码块,其他线程可以访问该对象的非synchronized(this)同步代码。如果类中包含多个synchronized(this)同步代码块,如果同步线程有一个访问其中一个代码块,则其他线程不能访问该对象的所有synchronized(this)同步代码块。对于下面形式的同步块而言,调用ClassName对象实例的并行线程中只有一个线程能够访问该对象。

synchronized( ClassName.class ){...}


0 0
原创粉丝点击