Java中级_多线程

线程

线程是进程中的一个实体

是被系统独立调度和分配的基本单位

一个标准的线程:

  1. 线程ID,
  2. 当前指令指针(PC)
  3. 寄存器集合
  4. 堆栈

Java默认线程有两个:

  1. main()主线程
  2. GC线程

线程状态

之前线程的状态

(1)新建状态(New):当线程对象对创建后,即进入了新建状态

(2)就绪状态(Runnable):当调用线程对象的start()方法,线程即进入就绪状态

(3)运行状态(Running):当CPU开始调度处于就绪状态的线程时,此时线程才得以真正执行,,执行run()方法

(4)阻塞状态(Blocked):处于运行状态中的线程由于某种原因,暂时放弃对CPU的使用权,停止执行

(5)死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

在Java中

在Thread.state源码来看 线程状态有6种

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public enum State {状态
// 新生
NEW,
// 运行状态
RUNNABLE,
// 阻塞状态
BLOCKED,
// 等待----一直等
WAITING,
// 超时等待---过时不候
TIMED_WAITING,
// 终止
TERMINATED;
}

1.初始(NEW):新创建了一个线程对象,但还没有调用start()方法。

2.运行(RUNNABLE):Java线程中将就绪(ready)和运行中(running)两种状态笼统的称为“运行”。
线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。该状态的线程位于可运行线程池 中,等待被线程调度选中,获取CPU的使用权,此时处于就绪状态(ready)。就绪状态的线程在获得CPU 时间片后变为运行中状态(running)。
3.阻塞(BLOCKED):表示线程阻塞于锁。
4.等待(WAITING):进入该状态的线程需要等待其他线程做出一些特定动作(通知或中断)。
5.超时等待(TIMED_WAITING):该状态不同于WAITING,它可以在指定的时间后自行返回。

6.终止(TERMINATED):表示该线程已经执行完毕。

Java无法开启一个线程: 通过调用本地方法来开启的

1
private native void start0();

多线程

实现Runnable接口,实现Callable和继承Thread可以得到一个线程类

为什么使用多线程?

为了解决负载均衡问题,充分利用单核的CPU资源.为了提高CPU的使用率,

继承Thread方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class ThreadTest extends Thread { // 线程主体
private String title;

public ThreadTest(String title) {
this.title = title;
}

@Override
public void run() { // 线程主方法
for (int i = 0; i < 3; i++) {
System.out.println(title + "--继承Thread类似创建线程");
}
}
}
1
2
3
4
5
6
7
8
9
public static void main(String[] args) {
// Thread
ThreadTest t1 = new ThreadTest("线程A");
ThreadTest t2 = new ThreadTest("线程B");
ThreadTest t3 = new ThreadTest("线程C");
t1.start(); // 在多线程操作之中,使用start()方法启动多线程的操作是需要进行操作系统函数调用的
t2.start();
t3.start();
}

结果:

线程A–继承Thread类似创建线程
线程B–继承Thread类似创建线程
线程C–继承Thread类似创建线程
线程B–继承Thread类似创建线程
线程A–继承Thread类似创建线程
线程B–继承Thread类似创建线程
线程C–继承Thread类似创建线程
线程A–继承Thread类似创建线程
线程C–继承Thread类似创建线程

实现Runable接口方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class RunableTest implements Runnable {// 线程主体
private String title;

public RunableTest(String title) {// 线程主方法
this.title = title;
}

@Override
public void run() {
for (int i = 0; i < 3; i++) {
System.out.println(title + "--实现Runable类似创建线程");
}
}
}
1
2
3
4
5
6
7
8
9
public static void main(String[] args) {
// Runable
RunableTest ta = new RunableTest("Runable-aa");
RunableTest tb = new RunableTest("Runable-bb");
RunableTest tc = new RunableTest("Runable-cc");
new Thread(ta).start(); // 借助Thread类的构造方法启动线程
new Thread(tb).start();
new Thread(tc).start();
}

结果:

Runable-aa–实现Runable类似创建线程
Runable-cc–实现Runable类似创建线程
Runable-bb–实现Runable类似创建线程
Runable-cc–实现Runable类似创建线程
Runable-aa–实现Runable类似创建线程
Runable-cc–实现Runable类似创建线程
Runable-bb–实现Runable类似创建线程
Runable-bb–实现Runable类似创建线程
Runable-aa–实现Runable类似创建线程

实现Callable方式

1
2
3
4
5
6
7
8
9
10
11
12
class CallableTest implements Callable<String> {
private String name;

@Override
public String call() throws Exception {
for (int i = 0; i < 3; i++) {
name = "" + i;
System.out.println("name:" + name);
}
return "测试结束";
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public static void main(String[] args) throws Exception {

// Callable
CallableTest c1 = new CallableTest();
CallableTest c2 = new CallableTest();
CallableTest c3 = new CallableTest();

//FutureTask是Runnable接口的子类,可以使用Thread类的构造来接收task对象
FutureTask<String> ft1 = new FutureTask<String>(c1);
FutureTask<String> ft2 = new FutureTask<String>(c2);
FutureTask<String> ft3 = new FutureTask<String>(c3);

new Thread(ft1).start();
new Thread(ft2).start();
new Thread(ft3).start();
//多线程执行完毕后,可以使用FutureTask的父接口Future中的get()方法取得执行结果
System.out.println("ft1:" + ft1.get());
System.out.println("ft2:" + ft2.get());
System.out.println("ft3:" + ft3.get());
}

结果:

name:0
name:0
name:0
name:1
name:1
name:2
name:1
name:2
name:2
ft1:测试结束
ft2:测试结束
ft3:测试结束

Runable与Callable区别:

不同点

Runnable没有返回值;Callable可以返回执行结果,是个泛型,和Future、FutureTask配合可以用来获取异步执行的结果

Callable接口的call()方法允许抛出异常;Runnable的run()方法异常只能在内部消化,不能往上继续抛

:Callalble接口支持返回执行结果,需要调用FutureTask.get()得到,此方法会阻塞主进程的继续往下执行,如果不调用不会阻塞。

关键字

Sleep

Thread.sleep(2000); 表示当前线程暂停1000毫秒 ,其他线程不受影响
Thread.sleep(2000); 会抛出InterruptedException 中断异常

1
2
3
4
5
6
7
8
9
10
11
12
13
@Override
public void run() { // 线程主方法
try {
Thread.sleep(2000);
System.out.println("...暂停了2秒才开始输出");
for (int i = 0; i < 3; i++) {
System.out.println(title + "--继承Thread类似创建线程");
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

Join

t3.join(3000); 3秒

把某一下线程加入到主线程,表示只有等该线程执行完成才继续运行其他线程

1
2
3
4
5
6
7
8
9
10
11
public static void main(String[] args) throws Exception {
// Thread
ThreadTest t1 = new ThreadTest("线程A");
ThreadTest t2 = new ThreadTest("线程B");
ThreadTest t3 = new ThreadTest("线程C");
t1.start(); // 在多线程操作之中,使用start()方法启动多线程的操作是需要进行操作系统函数调用的
t2.start();
t3.start();
//把t3线程加入到主线程 3秒
t3.join(3000);
}

setPriority

线程优先级

1
2
3
4
5
6
7
8
// 优先级最高
t1.setPriority(Thread.MAX_PRIORITY);
// 正常
t2.setPriority(Thread.NORM_PRIORITY);
// 优先级最低
t3.setPriority(Thread.MIN_PRIORITY);
// 可以使用数字
t4.setPriority(10);

yield

临时暂停

1
t3.yield();

setDaemon

守护线程

t1.setDaemon(true);设置当前线程为守护进程

1
t1.setDaemon(true);

小唠嗑:

想更加深入的了解多线程的使用,进看《Java中级_多线程二》篇

本章到这里就结束了,谢谢耐心看到这里的各位Boss,如果觉得有哪里说的不好的地方,还请高抬贵手多多原谅,不惜指教。

最后,谢谢!

---本文结束感谢您的阅读!---