举一个生活中的例子,你打开电脑听着音乐,同时你还在和自己的女朋友QQ聊天(哦!你没有女朋友),这个时候可以认为有两个进程,对于单核CPU来说并发运行是CPU时间钟快速轮询调度给我们的错觉,对于多核CPU来说才是真正意义上的并发运行。
1.1线程
一个进程中至少有一个线程(也被称为轻量级进程),线程是程序执行的路径,每个线程都有自己的局部变量表,程序计数器(指向正在执行的指令指针),以及各自的生命周期(这里看不懂没关系,回头来看就好,举个例子你在QQ中打开和某人的聊天界面,这个时候程序既要加载聊天记录,还要加载聊天界面,如果使用单线程(界面出来了聊天记录还没有),就会有不好的体验,这样能理解多线程了吧)
1.2快速创建并启动一个线程
为了大家更清楚,我简单说一下Thread类,大多数教程可能会这样描述,创建线程有两种方式(1.继承Thread并重写run方法 2.继承Runnable接口并重写run方法),这样说是不严谨的,why?我们来看下面的图
请看,Runnable接口只是定义了run()方法,并没有start方法,我们再来看一下Thread类源码
Thread实现了Runnable接口,而且还定义了start方法
等到后面我们用Runnable方式实现创建线程时会更清楚
进入正题
继承Thread类(java.lang包下的默认不用导包)
步骤:1.创建一个类,该类继承Thread类
步骤:2.重写run()方法
步骤:3.实例化创建类的对象
步骤:4.调用start方法()启动线程
public class test {
public static void main(String[] args) {
//第三步
Thread thread = new DemoThread();
//第四步
thread.start();
System.out.println("main方法");
}
}
//第一步
class DemoThread extends Thread{
//第二步
@Override
public void run() {
System.out.println("run方法");
}
}
如果我们运行多次会发现两个打印的先后顺序不是一定的,说明多线程在运行,为了更明显我们试试下面的代码
public class test {
public static void main(String[] args) throws InterruptedException {
Thread thread = new DemoThread();
thread.start();
for (int i = 0;i<=4;i++){
System.out.println("运行main方法");
Thread.sleep(100);
}
}
}
class DemoThread extends Thread{
@Override
public void run() {
for (int i = 0;i<=4;i++){
System.out.println("运行run方法");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
运行结果
关于start和sleep方法的详解后面会提到,这里只是看到并发编程的效果
实现Runnable接口
步骤:1.创建一个类,实现Runnable接口
步骤:2.重写run方法
步骤:3.创建实现类的实例对象
步骤:4.由于Runnable接口没有定义start方法,而Thread类中有如下构造函数,因此可以将该实例对象作为参数来创建线程
public class test {
public static void main(String[] args) throws InterruptedException {
DemoThread demoThread = new DemoThread();
Thread thread = new Thread(demoThread);
thread.start();
for (int i = 0;i<=4;i++){
System.out.println("运行main方法");
Thread.sleep(100);
}
}
}
class DemoThread implements Runnable{
@Override
public void run() {
for (int i = 0;i<=4;i++){
System.out.println("运行run方法");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
是不是只有亿点变化呀!
线程的生命周期
Thread类常见API
currentThread() | public static native Thread currentThread(); | 返回当前线程 |
getName() | public final String getName() { return name; } | 返回当前进程的名称(可配合currentThread方法) |
isAlive() | public final native boolean isAlive(); | 判断当前线程是否处于活跃状 |
成员变量和线程安全
共享数据 不共享数据
//共享数据
public class test {
public static void main(String[] args) throws InterruptedException {
DemoThread demoThread = new DemoThread();
Thread thread1 = new Thread(demoThread);
Thread thread2 = new Thread(demoThread);
Thread thread3 = new Thread(demoThread);
Thread thread4 = new Thread(demoThread);
Thread thread5 = new Thread(demoThread);
thread1.start();
thread2.start();
thread3.start();
thread4.start();
thread5.start();
}
}
class DemoThread implements Runnable{
private int num = 5;
@Override
public void run() {
while (num>0){
num--;
System.out.println(num);
}
}
}
//不共享数据
public class test {
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new DemoThread();
Thread thread2 = new DemoThread();
Thread thread3 = new DemoThread();
Thread thread4 = new DemoThread();
Thread thread5 = new DemoThread();
thread1.start();
thread2.start();
thread3.start();
thread4.start();
thread5.start();
}
}
class DemoThread extends Thread{
private int num = 5;
@Override
public void run() {
while (num>0){
num--;
System.out.println(num);
}
}
}