在说线程之前,有必要说下进程,进程是指程序的一次动态执行过程,或者说进程是正在执行中的程序,其占用特定的地址空间。现代的操作系统,如Windows和UNIX系统,都支持多任务处理,即将CPU的计算时间动态地划分给多个进程,这样操作系统可以同时运行多个进程,这些进程是相互隔离的。独立运行的程序。
相对于进程,线程是进程中一段连续的控制流程或是一段执行路径。它不能独立存在,必须存在于某个进程中。一个进程可以拥有多个线程,这些线程可以共享进程中内存单元,可以访问相同的变量和对象,以实现线程间通信,数据交换和同步操作等功能。
在java语言中线程的创建有两种方式:1.定义一个Thread类的子类,并在该类中重写run()方法,该run方法是线程执行的起点;2.定义一个实现Runnable接口的类,并在该类中定义Runnable接口的run()方法,还需要引用Thread类的构造方法,才能真正成为线程对象。
线程的状态: 一个线程对象从创建,启动,运行,终止,直到线程对象被java虚拟机所释放,其生命周期会处于以下四种状态“运行”,“暂停”,“同步”,“挂起”。一个线程对象调用了start()方法后,并不意味着该线程立刻被java虚拟机执行,该线程还需要通过java虚拟机 的调度等待分配给它的CPU计算资源。只有当线程得到了CPU计算资源,它才能真正执行run()方法中所包含的语言,这也是启动是引用start方法,而不是直接引run()方法的原因。
终止:
当线程对象run()方法中所包含的语句执行完毕,则该线程对象作为一独立的执行逻辑即终止,它就不能再运行了。但该线程对象仍然存在,对此可采用isAlive()方法来判断线程是正在执行当中,还是已经终止。
暂停:
暂停是指让正在执行的线程暂时停止运行,并在暂停一段时间后,再恢复运行。
sleep()方法是让线程“睡眠”即停止运行 所指定的一段时间,在睡眠结束后,线程立即恢复执行。
join()方法的作用是使当前运行的线程停下来等待,直至所引用join()方法的另一个线程终止。
同步:
当多个线程对同一数据或对象进行读/写操作时,就需要协调它们对数据的访问,使它们得到数据的一致视图,否则它们之间会互相干扰,在程序中产生不可预期的结果。这种协调机制称为线程的同步。
下面这个列子阐明线程间是如何实现同步的:
1 package com; 2 3 import java.util.Date; 4 5 public class Demo { 6 7 /** 8 * @param args 9 */ 10 public static void main(String[] args) { 11 // TODO Auto-generated method stub 12 CubbyHole ch = new CubbyHole(); 13 Producer p = new Producer(ch); 14 Consumer c = new Consumer(ch); 15 p.start(); 16 c.start(); 17 } 18 } 19 20 class CubbyHole { 21 22 private int content; 23 private boolean available = false; 24 25 public synchronized int get() { 26 27 while (available == false) { 28 try { 29 wait(); 30 } catch (InterruptedException e) { 31 System.out.println(e); 32 e.printStackTrace(); 33 } 34 } 35 36 available = false; 37 notifyAll(); 38 return content; 39 } 40 41 public synchronized void put(int value) { 42 43 while (available == true) { 44 try { 45 wait(); 46 } catch (InterruptedException e) { 47 System.out.println(e); 48 e.printStackTrace(); 49 } 50 } 51 content = value; 52 available = true; 53 notify(); 54 } 55 } 56 57 class Producer extends Thread { 58 59 private CubbyHole cubbyhole; 60 61 public Producer(CubbyHole c) { 62 cubbyhole = c; 63 } 64 65 public void run() { 66 for (int i = 0; i < 10; i++) { 67 cubbyhole.put(i); 68 System.out.println("Producer " + "put:" + i + ":" + new Date()); 69 try { 70 Thread.sleep((int) Math.random() * 1000); 71 } catch (InterruptedException e) { 72 System.out.println(e); 73 e.printStackTrace(); 74 } 75 } 76 } 77 } 78 79 class Consumer extends Thread { 80 81 private CubbyHole cubbyhole; 82 83 public Consumer(CubbyHole c) { 84 cubbyhole = c; 85 } 86 87 public void run() { 88 int value = 0; 89 for (int i = 0; i < 10; i++) { 90 value = cubbyhole.get(); 91 System.out 92 .println("Consumer " + " get:" + value + ":" + new Date()); 93 94 } 95 } 96 }
执行结果:
Producer put:0:Fri May 24 22:40:02 CST 2013
Consumer get:0:Fri May 24 22:40:02 CST 2013
Consumer get:1:Fri May 24 22:40:02 CST 2013
Producer put:1:Fri May 24 22:40:02 CST 2013
Consumer get:2:Fri May 24 22:40:02 CST 2013
Producer put:2:Fri May 24 22:40:02 CST 2013
Producer put:3:Fri May 24 22:40:02 CST 2013
Consumer get:3:Fri May 24 22:40:02 CST 2013
Consumer get:4:Fri May 24 22:40:02 CST 2013
Producer put:4:Fri May 24 22:40:02 CST 2013
Consumer get:5:Fri May 24 22:40:02 CST 2013
Producer put:5:Fri May 24 22:40:02 CST 2013
Producer put:6:Fri May 24 22:40:02 CST 2013
Consumer get:6:Fri May 24 22:40:02 CST 2013
Producer put:7:Fri May 24 22:40:02 CST 2013
Consumer get:7:Fri May 24 22:40:02 CST 2013
Producer put:8:Fri May 24 22:40:02 CST 2013
Consumer get:8:Fri May 24 22:40:02 CST 2013
Producer put:9:Fri May 24 22:40:02 CST 2013
Consumer get:9:Fri May 24 22:40:02 CST 2013
该实例主要描写了两个线程和一个共享对象间的操作。其中Producer线程是往共享对象CubbyHole中填数,而另一个Consumer线程则是从该共享对象中取数。
线程同步是通过如下两个方面来共同作用而实现的:一是通过关键词 synchronized 给关键对象或数据加锁,这里的关键对象即为CubbyHole对象,;另一方面是利用wait()和notify()方法实现线程间相互等待和唤醒。