你没看错,上面这张封面图为AMD推出的CPU,名为 ‘ 线程撕裂者 ’ ,霸气侧漏的命名反映出了它强悍的性能,而 ‘ 线程 ’ 究竟为何物,在Java中又如何应用呢?

一.概念

  • 进程
    • 是指可执行程序放在计算机存储器的一个指令序列,是一个动态执行的过程
  • 线程
    • 比进程还要小的运行单位,一个进程包含多个线程
    • CPU通过时间片轮转完成多任务

二.线程的创建

创建一个Thread类,或者一个Thread子类的对象

构造方法 说明
Thread() 创建一个线程对象
Thread(String name) 创建一个具有指定名称的线程对象
Thread(Runnable target) 创建一个基于Runnable接口实现类的线程对象
Thread(Runnable target, String name) 创建一个基于Runnable接口实现类,并且具有指定名称的线程对象

Thread类常用方法

方法 说明
public void run() 线程相关的代码在这个方法写,一般要重写
public void start() 启动线程的方法
public static void sleep(long t) 线程休眠(毫秒)
public void join() 优先执行调用join()方法的线程
public void getName() 获得线程名字

方法一:创建一个实现Runnable接口的类的对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//例子 使用该接口原因:Java不支持多继承/不打算重写Thread类其他方法
package com.imooc.runnable;

class PrintRunnable implements Runnable{
@Override
public void run() {
int i=1;
while(i<=10)
System.out.println(Thread.currentThread().getName() + "正在运行!"+(i++));
}
}

public class ThreadTest {

public static void main(String[] args) {
PrintRunnable pr = new PrintRunnable();
Thread t1 = new Thread(pr);
t1.start();

PrintRunnable pr1 = new PrintRunnable();
Thread t2 = new Thread(pr1);
t2.start();
}

}

方法二:匿名内部类线程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
while((s = br.readLine())!=null){
// 向匿名内部类传参
// jdk1.5 匿名内部类使用外部参数要用final 修饰外部参数
// jdk1.8 匿名内部类使用外部参数不需要使用final 修饰外部参数
String finalS = s;
new Thread(){
public void run(){
int b=0;
for(int i = 0; i< finalS.length(); i++){
if(finalS.substring(i,i+1).equals("b")){
b++;
}
}
// odd 'b'
if(b%2!=0){
System.out.printf(finalS + ":yes\n");
} else if(b%2==0){
System.out.printf(finalS + ":no\n");
}
}
}.start();
}

创建线程的两种方式总结

方式 启动
通过继承Thread类创建线程(MyThread为例) new MyThread().start()
通过实现Runnable接口创建线程(MyRunnable为例) new Thread(new MyRunnable()).start()

三.线程的状态和生命周期

状态 说明
新建(New) 创建线程对象
可运行(Runnable) 获取CPU使用权变为正在运行状态
正在运行(Running) 时间片用完回到可运行状态
阻塞(Blocked) join() / wait() / sleep() / IO请求,调用notify()或等待join()线程执行完毕,sleep超时,I/O请求完成时回到可运行状态
终止(Dead) 调用stop()方法进入终止状态

进入阻塞状态的方法

方法名 作用
public static void sleep(long millis) 在指定的毫秒数内让正在执行的线程休眠
public final void join() 等待调用该方法的线程结束后才能执行其他线程
public final void join(long millis) 等待该线程终止的最长时间为(毫秒)

线程的优先级别(主线程默认为5)

优先级常量 说明
MAX_PRIORITY 线程最高优先级10
MIN_PRIORITY 线程最低优先级1
NORM_PRIORITY 线程默认优先级5
方法 说明
public int getPriority() 获取线程优先级的方法
public void setPriority(int newPriority) 设置线程优先级的方法

四.线程同步

典例:存取款问题

为了保证在存取款时,不允许其他线程对账户余额进行操作,需要对实体类锁定

synchronized 关键字部位 [ˈsɪŋkrənaɪzd] 示例
成员方法 public synchronized void saveAccount(){}
静态方法 public static synchronized void saveAccount(){}
语句块 synchronized(obj){…}

五.线程间通信

方法 说明
wait() 中断方法的执行,使线程等待
notify() 唤醒处于等待的某一个线程,使其结束等待
notifyAll() 唤醒所有处于等待状态的线程
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
//使用容器类,生产一次消费一次模拟存取款
public class Queue {
private int n;

boolean flag = false;

public synchronized int get() {
if(!flag){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("消费:"+n);
flag = false; //消费完毕,容器中没有数据
notifyAll(); //防止死锁
return n;
}

public synchronized void set(int n) {
if(flag){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("生产:"+n);
this.n = n;
flag = true; //生产完毕,容器中有数据
notifyAll(); //防止死锁
}
}