概述
多线程程序包含两个或多个可同时运行的部分,每个部分可以同时处理不同的任务,从而能更好地利用可用资源,特别是当计算机有多个CPU的时候。
多线程够写入多个活动,可以在同一程序中同时进行操作处理。
根据定义,多任务是当多个进程共享,如CPU处理公共资源。
多线程将多任务的概念扩展到可以将单个应用程序中的特定操作细分为单个线程的应用程序。每个线程可以并行运行。
操作系统不仅在不同的应用程序之间划分处理时间,而且在应用程序中的每个线程之间划分处理时间。
多线程能够在同一程序同中,进行多个活动的方式进行写入。
线程的生命周期
线程从创建到运行完成要经历下面这些阶段:
- New
- Runnable
- Running
- Non-Runnable (blocked) / Waiting
- Terminated
New: 该状态指已经创建了该线程类的实例,但是还没有调用 start() 方法。
Runnable: 该状态指线程已经调用了 start() 方法,已经可以运行了,正在等待线程调度器来运行。
Running: 该状态指此线程已经被线程调度器选中并正在运行中。
Non-Runnable (blocked): 该状态指线程还存在但是没有资格运行。可能的原因有:sleep 操作、等待文件 I/O 的完成或等待释放锁状态等等。
Terminated: 该状态指线程已经运行结束,处于中止状态, run() 方法已经退出。
线程优先级
每个Java线程都有一个优先级,可以帮助操作系统确定安排线程的顺序。
Java线程优先级在MIN_PRIORITY(常数为1)和MAX_PRIORITY(常数为10)之间的范围内。
默认情况下,每个线程都被赋予优先级NORM_PRIORITY(常数为5)。
具有较高优先级的线程对于一个程序来说更重要,应该在低优先级线程之前分配处理器时间。 然而,线程优先级不能保证线程执行的顺序,并且依赖于平台。
创建线程的两种方式
通过实现Runnable接口创建一个线程
- 第一步:
实现由Runnable接口提供的run()方法。 该方法为线程提供了一个入口点,该方法中存放完整的业务逻辑。
public void run()
- 第二步:
实例化一个Thread对象,通过Thread提供的以下构造函数
Thread(Runnable threadObj, String threadName);
threadObj:实现Runnable接口的类的实例
threadName :新线程的名称
- 第三步:
创建了一个线程对象,可以通过调用start()方法启动它,该方法执行对run()方法的调用.
package com.xgj.master.java.concurrency; public class RunnableDemo implements Runnable { private String threadName; private Thread thread; /** * * @Title:CreateThreadByRunnable * @Description:构造函数 * @param threadName */ public RunnableDemo(String threadName) { this.threadName = threadName; System.out.println("Create thread:" + threadName); } /** * * @Title: run * @Description: 重写Runnable接口中的run方法,业务逻辑存在与该方法中 * @return: void */ @Override public void run() { System.out.println("Running " + threadName ); try { for (int i = 0 ; i < 5 ; i++) { System.out.println("ThreadName:" + threadName + " : " + i); // 睡眠0.5秒 Thread.sleep(500); } } catch (InterruptedException e) { e.printStackTrace(); System.out.println("Thread " + threadName + " interrupted."); } System.out.println("Thread " + threadName + " exiting."); } /** * * @Title: startThread * @Description: 如果线程对象为空,创建并启动线程 ,通过调用thread.start()方法启动线程,该方法执行对run()方法的调用. * @return: void */ public void startThread(){ if( thread == null){ thread = new Thread(this, threadName); thread.start(); } } }
package com.xgj.master.java.concurrency; public class RunnableDemoTest { public static void main(String[] args) { RunnableDemo thread1 = new RunnableDemo("thread-1"); thread1.startThread(); RunnableDemo thread2 = new RunnableDemo("thread-2"); thread2.startThread(); } }
运行结果(每次运行的结果不尽相同)
Create thread:thread-1 Create thread:thread-2 Running thread-1 ThreadName:thread-1 : 0 Running thread-2 ThreadName:thread-2 : 0 ThreadName:thread-1 : 1 ThreadName:thread-2 : 1 ThreadName:thread-1 : 2 ThreadName:thread-2 : 2 ThreadName:thread-1 : 3 ThreadName:thread-2 : 3 ThreadName:thread-2 : 4 ThreadName:thread-1 : 4 Thread thread-1 exiting. Thread thread-2 exiting.
通过扩展Thread类创建一个线程
我们通过继承Thread类,来重写上面的例子
package com.xgj.master.java.concurrency; public class ThreadDemo extends Thread { private Thread t; private String threadName; /** * * @Title:ThreadDemo * @Description:构造函数,实例化一个带有ThreadName的线程 * @param threadName */ public ThreadDemo(String threadName) { this.threadName = threadName; System.out.println("Creating " + threadName); } /** * * @Title: run * @Description: 业务逻辑存在与该方法中 * @return: void */ public void run() { System.out.println("Running " + threadName); try { for (int i = 0; i < 5; i++) { System.out.println("Thread: " + threadName + ", " + i); // 睡眠0.5秒 Thread.sleep(500); } } catch (InterruptedException e) { System.out.println("Thread " + threadName + " interrupted."); } System.out.println("Thread " + threadName + " exiting."); } /** * * @Title: startThread * @Description: 如果线程对象为空,创建并启动线程 ,通过调用thread.start()方法启动线程,该方法执行对run()方法的调用. * @return: void */ public void startThread() { System.out.println("Starting " + threadName); if (t == null) { t = new Thread(this, threadName); t.start(); } } }
package com.xgj.master.java.concurrency; public class ThreadDemoTest { public static void main(String[] args) { ThreadDemo threadDemo1 = new ThreadDemo("Thread-1"); threadDemo1.start(); ThreadDemo threadDemo2 = new ThreadDemo("Thread-2"); threadDemo2.start(); } }
运行结果(每次运行的结果不尽相同)
Creating Thread-1 Creating Thread-2 Running Thread-1 Thread: Thread-1, 0 Running Thread-2 Thread: Thread-2, 0 Thread: Thread-2, 1 Thread: Thread-1, 1 Thread: Thread-1, 2 Thread: Thread-2, 2 Thread: Thread-2, 3 Thread: Thread-1, 3 Thread: Thread-2, 4 Thread: Thread-1, 4 Thread Thread-1 exiting. Thread Thread-2 exiting.
线程的主要操作
- 已废弃 public void suspend() 该方法使线程处于挂起状态,可以使用resume()方法恢复。
- 已废弃 public void stop() 该方法使线程完全停止。
- 已废弃 public void resume() 该方法恢复使用suspend()方法挂起的线程。
- public void wait() 导致当前线程等到另一个线程调用notify()。
- public void notify() 唤醒在此对象监视器上等待的单个线程。
JDK1.2之后已经不再使用suspend(),resume()和stop()方法。
Thread.stop()废弃原因
stop方法会解除被加锁的对象的锁,因而可能造成这些对象处于不一致的状态,而且这个方法造成的ThreadDeath异常不像其他的检查期异常一样被捕获。
可以使用interrupt方法代替。
事实上,如果一个方法不能被interrupt,那stop方法也不会起作用。
Thread.suspend()、resume()废弃原因
suspend/resume方法容易发生死锁。
使用suspend时,并不会释放锁;假设先获取该锁,再进行resume,就会造成死锁。
可以使用Object的wait和notify方法代替。wait方法会释放持有的锁。
线程间通信
主要方法
- public void wait() 使当前线程等到另一个线程调用notify()方法。
- public void notify() 唤醒在此对象监视器上等待的单个线程。
- public void notifyAll() 唤醒所有在同一个对象上调用wait()的线程。
上述几个方法方法已被实现为Object中的final方法,因此它们在所有类中都可用。 所有这三种方法只能从同步上下文中调用。