进程:一个进程包括由系统分配的内存空间,包括一个或多个线程,一个线程不能独立存在,它必是进程的一部分。一个进程一直运行,知道所有的非守候线程都结束后才能结束。
多线程能满足程序员编写高效率的程序来达到充分利用 CPU 的目的。
一个线程的生命周期:
- 新建状态:线程对象被创建后的状态
- 就绪状态:线程对象调用start()方法后,该线程就进入就绪状态。就绪状态的线程处于就绪队列中,要等待JVM里线程调度器的调度
- 运行状态:如果就绪状态的线程获取CPU资源,就可以执行run(),此时线程便处于运行状态。处于运行状态的线程最为复杂,它可以变为阻塞状态、就绪状态和死亡状态
- 阻塞状态:如果一个线程执行了sleep(睡眠)、suspend(挂起)等方法,失去所占用资源之后,该线程就从运行状态进入阻塞状态。在睡眠时间已到或获得设备资源后可以重新进入就绪状态。可以分为三种:
- 等待阻塞:运行状态中的线程执行wait()方法,使线程进入到等待阻塞状态
- 同步阻塞:线程在获取 synchronized 同步锁失败(因为同步锁被其他线程占用)
- 其他阻塞:通过调用线程的 sleep() 或 join() 发出了 I/O 请求时,线程就会进入到阻塞状态。当sleep() 状态超时,join() 等待线程终止或超时,或者 I/O 处理完毕,线程重新转入就绪状态。
- 一个运行状态的线程完成任务或者其他终止条件发生时,该线程就切换到终止状态。
线程的优先级:
每一个 Java 线程都有一个优先级,这样有助于操作系统确定线程的调度顺序。
Java 线程的优先级是一个整数,其取值范围是 1 (Thread.MIN_PRIORITY ) - 10 (Thread.MAX_PRIORITY )。
默认情况下,每一个线程都会分配一个优先级 NORM_PRIORITY(5)。
具有较高优先级的线程对程序更重要,并且应该在低优先级的线程之前分配处理器资源。但是,线程优先级不能保证线程执行的顺序,而且非常依赖于平台。
创建一个线程:
通过实现Runnable接口来创建线程:
为实现Runnable接口,须实现run()方法:public void run();
在创建一个实现 Runnable 接口的类之后,可以在类中实例化一个线程对象。
Thread 定义了几个构造方法,下面的这个是我们经常使用的:
Thread(Runnable threadOb,String threadName);
第一个参数为实现Runnable接口的对象,第二个为线程名称
新建线程后,必须调用它的start()方法才会运行
实例:
1 public class DateDemo{ 2 public static void main(String[] args) { 3 RunnableDemo R1 = new RunnableDemo("one"); 4 RunnableDemo R2 = new RunnableDemo("two"); 5 R1.start(); 6 R2.start(); 7 } 8 } 9 class RunnableDemo implements Runnable{ 10 11 private String threadName; 12 private Thread thread; 13 RunnableDemo(String threadName) { 14 this.threadName = threadName; 15 } 16 @Override 17 public void run() { 18 System.out.println(threadName + " 1"); 19 try { 20 thread.sleep(3000); 21 } catch (InterruptedException e) { 22 // TODO Auto-generated catch block 23 e.printStackTrace(); 24 } 25 System.out.println(threadName + " 1"); 26 } 27 public void start() { 28 thread = new Thread(this,threadName); 29 thread.start(); 30 } 31 }
通过继承Thread来创建多线程:
创建一个线程的第二种方法是创建一个新的类,该类继承 Thread 类,然后创建一个该类的实例。
继承类必须重写 run() 方法,该方法是新线程的入口点。它也必须调用 start() 方法才能执行。
该方法尽管被列为一种多线程实现方式,但是本质上也是实现了 Runnable 接口的一个实例。
1 class ThreadDemo extends Thread { 2 private Thread t; 3 private String threadName; 4 5 ThreadDemo( String name) { 6 threadName = name; 7 System.out.println("Creating " + threadName ); 8 } 9 10 public void run() { 11 System.out.println("Running " + threadName ); 12 try { 13 for(int i = 4; i > 0; i--) { 14 System.out.println("Thread: " + threadName + ", " + i); 15 // 让线程睡眠一会 16 Thread.sleep(50); 17 } 18 }catch (InterruptedException e) { 19 System.out.println("Thread " + threadName + " interrupted."); 20 } 21 System.out.println("Thread " + threadName + " exiting."); 22 } 23 24 public void start () { 25 System.out.println("Starting " + threadName ); 26 if (t == null) { 27 t = new Thread (this, threadName); 28 t.start (); 29 } 30 } 31 } 32 33 public class TestThread { 34 35 public static void main(String args[]) { 36 ThreadDemo T1 = new ThreadDemo( "Thread-1"); 37 T1.start(); 38 39 ThreadDemo T2 = new ThreadDemo( "Thread-2"); 40 T2.start(); 41 } 42 }
thread的常用方法:
序号 | 方法描述 |
---|---|
1 | public void start() 使该线程开始执行;Java 虚拟机调用该线程的 run 方法。 |
2 |
public void run() 如果该线程是使用独立的 Runnable 运行对象构造的,则调用该 Runnable 对象的 run 方法;否则,该方法不执行任何操作并返回。 |
3 |
public final void setName(String name) 改变线程名称,使之与参数 name 相同。 |
4 |
public final void setPriority(int priority) 更改线程的优先级。 |
5 |
public final void setDaemon(boolean on) 将该线程标记为守护线程或用户线程。 |
6 |
public final void join(long millisec) 等待该线程终止的时间最长为 millis 毫秒。 |
7 |
public void interrupt() 中断线程。 |
8 |
public final boolean isAlive() 测试线程是否处于活动状态。 |
测试线程是否处于活动状态。 上述方法是被Thread对象调用的。下面的方法是Thread类的静态方法。
序号 | 方法描述 |
---|---|
1 | public static void yield() 暂停当前正在执行的线程对象,并执行其他线程。 |
2 |
public static void sleep(long millisec) 在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。 |
3 |
public static boolean holdsLock(Object x) 当且仅当当前线程在指定的对象上保持监视器锁时,才返回 true。 |
4 |
public static Thread currentThread() 返回对当前正在执行的线程对象的引用。 |
5 |
public static void dumpStack() 将当前线程的堆栈跟踪打印至标准错误流。 |