Java线程初探
最近一段时间初学了一些java线程,写些体会,供大家一起交流学习。之前,一直都是编写单线程java程序,现在,初步学习线程,实现多线程的编写。
线程是程序中一个单一的顺序控制流程,而进程是指一个内存中运行的应用程序。每个进程都有自己独立的一块内存空间,可以启动多个线程,这些多线程共享进程的内存。多线程的执行是并发的,也就是在逻辑上的同时。
简单了解些线程的状态。线程对象一旦被创建后,就进入初始状态。当该对象调用start方法,就进入可运行状态。此后,当该对象被操作系统选中,获得CPU时间片就会进入运行状态。关于可运行状态和运行状态,就好比短跑中,一个是预备跑状态,一个是开跑以后状态。一个是具备了条件但没有去做,一个是已经做开了。进入运行状态后就可能会出现以下多种情况:
(1)如果run方法或main方法结束,则线程进入终止状态。
(2)如果线程调用了自身的sleep方法或其他线程的join方法,就会进入阻塞状态。当此方法结束后,该线程进入可运行状态,继续等待操作系统分配时间片。
(3)如果线程调用了yield方法,回到可运行状态,这时与其他线程处于同等竞争状态,操作系统有可能会接着又让这个线程进入运行状态。
(4)当线程刚进入可运行状态时,发现将要调用的资源被同步,获取不到锁标记,将会立即进入锁池状态,等待获取锁标记。一旦线程获得锁标记后,就转入可运行状态,等待操作系统分配CPU时间片。
(5)如果线程调用wait方法,会进入等待队列,进入这个状态后,是不能自动唤醒的,必须依靠其他线程调用notify或notifyAll方法才能被唤醒,线程被唤醒后进入锁池,等待获取锁标记。
对于(4),(5)看不懂的不要急,它们涉及到多线程的同步,后面会讲。(这里穿插介绍一个isAlive方法,用来判断线程是在运行中还是已经终止。具体运用见下图:
public static void main(String[] args) {
Judge test1=new Judge(1000,"test1");
test1.start();
Judge test2=new Judge(2000,"test2");
test2.start();
System.out.println(test1.isAlive()?"运行中":"已经终止");
System.out.println(test2.isAlive()?"运行中":"已经终止");
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
System.out.println(e);
}
System.out.println(test1.isAlive()?"运行中":"已经终止");
System.out.println(test2.isAlive()?"运行中":"已经终止");
}
)
现在再肤浅的认识一下线程优先级。java给每个线程安排优先级以决定与其他线程比较时该如何对待该线程。线程优先级是详细说明线程间优先关系的整数。作为绝对值,优先级毫无意义的;当只有一个线程时。优先级高的线程并不比优先级低的线程运行得快。相反,线程的优先级是用来决定何时从一个运行的线程切换到另一个,叫做上下文转换。决定上下文转换发生的规则:1>.线程可以自动放弃控制。在I/O未决定的情况下,睡眠或阻塞由明确的让步来完成。在这种假定下,所有其他的线程被检测,准备运行的最高优先级线程被授予CPU。2>.线程可以被高优先级的线程抢占。在这种情况下,虽然低优先级线程不主动放弃,但是无论处理器正在干什么,它都会被高优先级的线程占据。基本上,一旦高优先级线程要运行,它就执行,这叫做有优先级的多任务处理,具体代码如下:
package 线程优先级;
public class MyRunnable implements Runnable{
public void run() {
for(int i=0;i<10;i++){
System.out.println("线程2第"+i+"次执行");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
package 线程优先级;
public class MyThread1 extends Thread {
public void run() {
for(int i=0;i<10;i++){
System.out.println("线程1第"+i+"次执行");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
package 线程优先级;
public class Priority {
public static void main(String[] args) {
Thread test1 = new MyThread1();
Thread test2 = new Thread(new MyRunnable());
// 创建了两个线程test1和test2,并且分别为其设置了优先级为10和1
test1.setPriority(10);
test2.setPriority(1);
test1.start();
test2.start();
}
}
由于前面相应例子已经有关于多线程的实现,这里就简单提一下。第一种:继承Thread类,Thread类有两种构造方法:public Thread(),public Thread(Runnable r)(参数r成为被创建的目标对象。这个目标必须实现Runnable接口,给出该接口的run()方法的方法体,在方法体中实现操作),这种方式需要作为一个线程执行的类只能继承,扩充单一的父类;第二种:实现Runnable接口,它打破了扩充Thread类方式的限制。如果有一个类,它已继承了某个类,又想实现多线程,那就可以通过实现Runnable接口来创建线程。
(注:本文资源来源于清华大学出版社的《高级程序设计语言(Java版)》,无任何商业目的,只是交流学习。)