一、引入多线程
请看上图中的代码执行流程,就可以大概的理解多线程。说到多线程就一定会联系到单线程,所谓单线程就是程序只有一条执行路径。相反,多线程就是程序有多条执行路径。
二、进程的概述
1.要想了解多线程,必须先了解线程。了解线程就必须先了解进程。因为线程依赖于进程。
2.什么是进程:就是正在运行中的程序。进程是系统进行资源分配和调度的独立单位,每一个进程都有自己独立的内存空间和系统资源。
3.多进程的意义:在同一时间段内可以执行多个任务,极大的提高了CPU的使用率。单核的CPU在某一时刻只能执行一个任务。
三、线程的概述
1.什么是线程:在同一个进程中又可以执行多个任务,而这每一个任务可以看成一个线程。线程是程序执行路径和执行单元,是程序使用CPU的基本单元。
2.多线程的意义:不是提高程序的执行速度的,而是提高应用程序的使用率的。程序的执行其实都在抢CPU资源和CPU的执行权。多个进程都在争夺CPU这一资源,而其中一进程有多个执行路径,抢到这一资源的几率就更高。但线程的执行是由随机性的。
四、并行和并发
并行:逻辑上同时发生,是指在同一时间内同时运行多个程序。
并发:物理上同时发生,是指在同一时间点上同时运行多个程序。
五、Java程序运行原理
执行Java命令就会启动Java虚拟机,启动JVM就等于启动了一个应用程序,也就是启动了一个进程,该进程会自动启动一个主线程。然后,主线程会去调用某个类的main方法,所以main方法时运行在主线程中的。
通过上图,可以看到启动一个Java程序,就会启动一个线程,在该线程中调用main方法。
JVM的启动是多线程的:在运行一个Java程序的时候,在启动主线程的时候,也会启动垃圾回收线程,否则会出现内存溢出。
六、创建线程的方式
1. 继承java.lang.Thread类,重写run()方法,创建线程对象并启动线程。
package com.jd; /** * Created by shifeifei on 2015/8/12. */ public class MyThread extends Thread { public static void main(String[] args) { MyThread t = new MyThread(); /** * run():仅仅是封装了线程执行的代码,直接调用就是普通方法 * start():首先启动了线程,然后由JVM去调用run()方法 */ t.start(); /** *要启动多个线程,必须先创建多个线程对象,再调start()方法 */ MyThread t2 = new MyThread(); t2.start(); } @Override public void run() { for(int i=0;i<200;i++) { System.out.println("当前线程是:"+ this.getName() + " " + i); } } }获取线程名称的方法是:public final String getName(),该方法返回的线程名称形式是:Thread-?(?代表0、1、2等自然数),为什么会是这种形式呢?我们开源码解析:
由于MyThread类继承与Thread类,进入到Thread类,我们可以看到如下代码:
private static int threadInitNumber; public Thread() { init(null, null, "Thread-" + nextThreadNum(), 0); } private static synchronized int nextThreadNum() { return threadInitNumber++; } private char name[]; private void init(ThreadGroup g, Runnable target, String name, long stackSize) { this.name = name.toCharArray(); } public final String getName() { return String.valueOf(name); }即在创建线程对象的时候,就调用init()方法。
既然能够获取线程的名称,我们也能够设置线程的名称,常用的方式有两种:调用public final void setName(String name)和
public Thread(String name)
- 线程调度
(1) 分时调度模型:所有线程轮流使用CPU的执行权,平均分配每个线程占用CPU的时间片。
(2) 抢占式调度模型:优先级高的线程优先使用CPU执行权,如果线程的优先级相同,就会随机选择一个执行,优先级高的线程获取CPU使用权多一些。
(3) Java中使用抢占式调度模型。
线程的优先是从1 - 10,默认的优先级为 5.Thread类定义了2个常量:MIN_PRIORITY和MAX_PRIORITY来表示最高和最低优先级。
1.获取线程的优先级:public final int getPriority()
2.设置线程的优先级:public final void setPriority(int newPriority)
package com.jd; /** * Created by shifeifei on 2015/8/13. * */ public class ThreadPriority extends Thread { @Override public void run() { for(int i=0;i<100;i++) { System.out.println(this.getName() + " " + i); } } public static void main(String[] args) { ThreadPriority t1 = new ThreadPriority(); ThreadPriority t2 = new ThreadPriority(); System.out.println(t1.getPriority() + " " + t2.getPriority()); t1.start(); t1.setPriority(10); t2.start(); t2.setPriority(1); } }3.线程信息
package com.jd; /** * Created by shifeifei on 2015/8/12. */ public class MyTestOne { public static void main(String[] args) { //Thread.currentThread()返回当前线程的引用 String name = Thread.currentThread().getName(); int priority = Thread.currentThread().getPriority(); String groupName = Thread.currentThread().getThreadGroup().getName(); boolean isDaemon = Thread.currentThread().isDaemon(); System.out.println("线程名字: " + name); System.out.println("线程优先级: " + priority); System.out.println("线程组名称: " + groupName); System.out.println("是否为守护线程: " + isDaemon); } }
- 守护线程和用户线程
1. 守护线程:Java程序运行时后台提供的一种通用服务的线程。守护线程是用来服务用户线程的,如果全部的用户线程结束了,守护线程也就结束了。
package com.jd; /** * Created by shifeifei on 2015/8/12. */ public class MyThread extends Thread { public static void main(String[] args) { Thread t1 = new Thread("daemon") { @Override public void run() { Thread t2 = new Thread("sub") { @Override public void run() { for (int i = 0; i < 20; i++) { System.out.println(this.getName() + " " + i); } } }; t2.setDaemon(true); t2.start(); } }; t1.start(); } }注意:(1) 所有的用户线程结束时,JVM就可以退出了。
(2) 设置当前线程为守护线程时必须在start()方法之前。
(3) 在Daemon线程中产生的新线程也是Daemon的。
(4) 守护线程应该永远不去访问固有资源,如文件、数据库,因为它会在任何时候甚至在一个操作的中间发生中断。
- GroupName,每个线程都会默认在一个线程组里,我们也可以显式的创建线程组,一个线程组中也可以包含子线程组,这样线程和线程组,就构成了一个树状结构。