Java线程是一个执行上下文或者一个轻量级的进程,它是程序里的一个单一连续的控制流。
程序员可以使用java线程机制同时执行多个任务。
Thread类和run()方法
java.lang.Thread类为线程提供了底层支持,并且提供了一个线程的API和线程的所有行为。这些行为包括开始(start),睡眠(sleeping),运行(running),让步(yielding)和获得优先权。
run()方法里指明线程需要做什么,这里的代码用了实现线程的行为,有两种方法创建自己的线程:
1.继承java.lang.Thread类并且重写run()方法。
2.实现java.lang.Runnable接口。
线程调度
我们常说线程是并发运行的,实际上不是那样的。在单一cpu的电脑,实际上一次只运行一个线程(每个线程轮流执行一小段时间),给我们是并发运行的假象。单一cpu的电脑上执行多线程是基于线程调度算法。线程调度维护线程池,所有准备运行(ready-to-run)的线程都在线程池里,基于固定优先级算法,分配空闲的cup给线程池中的某个线程。
线程的生命周期如图所示,图反映了java线程可以在生命周期里的任何一个状态点通过调用各种方法变为其他的状态点。
准备运行(Ready-to-run)
通过调用start()方法使线程开始其生命周期,例如:
MyThread aThread = new MyThread();
aThread.start();
线程调用start()方法并不会马上执行,而是被放到线程池中等待,直到轮到他执行。线程调度算法会根据线程的优先级选取一个准备运行的线程去运行。
运行(Running)
线程代码由处理器运行,一直运行直到被换出,当被阻塞或者自动调用静态方法yield()也会被换出。注意yield()是一个静态方法,任何线程对象都可以调用,它使当前执行线程放弃cup。
等待(Waiting)
调用 java.lang.Objec的等待方法会使当前线程进入等待状态。线程保持在等待状态直到另一个线程调用此对象的notify()方法或者notifyAll()方法。当前线程必须拥有自己的对象监视器去调用wait()方法。
睡眠(sleeping)
Java线程可能被强制睡眠(暂停)一些预定的时间。
Thread.sleep(milliseconds);
Thread.sleep(milliseconds, nanoseconds);
请注意,静态方法sleep()只能保证线程将睡眠预定的时间,预定时间过去后还需要花一些时间才能运行。例如,调用sleep(60)将会使当前执行的线程睡眠60毫秒,线程睡眠60毫秒后进入准备运行状态,他只有当调度器使他运行的时候才进入运行状态,因此我们只能说线程会在睡眠60毫秒后的一段时间运行,即不一定睡眠后马上就能执行。
I/O口阻塞
同步阻塞
Java线程可能在等待对象锁的时候进入这一状态,当获得对象锁后线程进入“准备运行”状态。
死掉(Dead)
当线程工作结束后就能进入这个状态,也有可能是因为不可恢复的错误条件终止了线程而使线程死掉。
线程同步
当两个线程都尝试访问或者修改同一个对象可能会出问题,为了防止这种情况发生,java使用监视器和同步关键字来控制一个时间只有一个线程访问该对象。
监视器(Monitor)
监视器在任何有同步代码的类里。
监视器使用 wait() ,notify() ( 或者notifyAll() ) 方法控制线程,wait() ,notify() 方法必须在同步代码里调用。如果线程不可使用,监视器会让线程等待。
通常会在while循环中调用wait()方法,while循环的条件一般是检测监视器是否有效,在等待结束后,线程从等待点恢复执行。
同步代码和锁
每一个对象都有一个锁,这锁一次最多只能被一个线程控制,锁控制着同步代码的访问。当运行的线程遇到同步代码声明时,他会进入阻塞状态,等待直到获得对象锁。获得锁之后,便执行同步代码块,然后释放对象锁。当执行的线程拥有锁时,其他的线程不能获得锁。因此锁和同步机制能保证多线程正确的执行代码。
线程优先级
线程的优先级是从1(最低)到10(最高)的整数,也可以使用常数 Thread.MIN_PRIORITY 和Thread.MAX_PRIORITY 。默认的情况下,setPriority()方法会设置线程的优先级为5,即常数Thread.NORM_PRIORITY。
Thread aThread = Thread.currentThread();
int currentPriority;
currentPriority = aThread.getPriority();
aThread.setPriority( currentPriority + 1 );
因为优先级方案在不同的平台实现不同,所以设置优先级也又可能不像期望的效果那样。如果所有线程都使用高优先级会频繁阻塞(睡眠或者等待I/O)。为cpu密集型使用中等到低的优先级线程来避免处理器停机。
线程死锁
在多线程中,可能会出现下面的情形:
当两个或者多个线程都尝试获取同一个对象的控制权会发生死锁或者抱死,每一个线程都锁住了另一个线程运行所需资源。
例如:线程A等着锁住对象P同时又拿着对象Q的锁,线程B拿着对象P的锁同时在等着锁住对象Q,他们都需要对方让出锁,死锁发生了。
请注意如果线程拿着锁进入随眠状态,他不会是释放锁,但是,当线程进入阻塞状态,通常会释放锁,这消除了线程潜在的死锁可能。
Java没有为死锁提供任何检测或者控制的机制,所以程序员要自己避免死锁发生。
原文地址:http://www.bpurcell.org/blog/index.cfm?mode=entry&entry=934