01-线程

image-20220320091718212

1. 线程创建

进程:程序静止的,真正运行时的程序,才被称为进程。
线程:轻量级进程(Light Weight Process),程序中的一个顺序控制流程,同时也是CPU的基本调度单位,进程由1个或多个线程组成,彼此间完成不同的工作,交替执行,称为多线程。

JVM,**Java虚拟机是一个进程(单进程)**,当中默认包含主线程(main),可通过代码创建多个独立线程,与main并发执行。

线程组成
① CPU时间片:操作系统会为每个线程分配执行时间;
② 运行数据:

  • 堆空间:存储线程需使用的对象,多个线程可以共享堆中的对象;
  • 栈空间:存储线程需使用的局部变量,每个线程都拥有独立的栈;
    ③ 线程的逻辑代码。

① 继承父类 - Thread

① 继承Thread类
② 覆盖run()方法
③ 创建子类对象
④ 调用start()方法 - 启动线程

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 TestExtendsThread {
public static void main(String[] args) { // 主线程
/**
* ③ 创建线程对象
*/
MyThread t1 = new MyThread();
//t1.run(); // 不能直接调用:run方法就是普通对象调用方法一样
/**
* ④ 调用start()方法,由JVM来调用run方法启动一个线程
*/
t1.start();

for (int i = 1; i <= 50; i++) {
System.out.println("Main:" + i);
}
}
}
/**
* ① 继承 Thread 类
*/
class MyThread extends Thread {
/**
* ② 覆盖run()方法,为线程的任务
*/
@Override
public void run() {
for (int i = 1; i <= 50; i++) {
System.out.println("MyThread:" + i);
}
}
}

② 实现接口 - Runnable

① 实现Runnable接口
② 覆盖run()方法
③ 创建实现类对象
④ 创建线程对象(Thread父类有参构造)
⑤ 调用start()方法 - 启动线程

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
35
36
37
38
39
40
41
public class TestImplementsRunnable {
public static void main(String[] args) {
/**
* ③ 创建实现类对象
*/
MyRunnable mr = new MyRunnable();
/**
* ④ 创建线程对象
*/
Thread t1 = new Thread(mr);
Thread t2 = new Thread(mr);
/**
* ⑤ 调用start()启动线程
*/
t1.start();
t2.start();

for (int i = 1; i <= 50; i++) {
System.out.println("Main:" + i);
}
}
}
/**
* ① 实现Runnable接口
* 特点:
* 1.只是将当前类变成线程任务类,本身不是个线程
* 2.任务是可以多线程对象共享(任务复用)
* 3.更灵活(还可以继承其他的类 + 实现其他的接口能力)
*/
class MyRunnable implements Runnable {
/**
* ② 覆盖run()方法
*/
public void run() {
for (int i = 1; i <= 50; i++) {
// Thread.currentThread().getId() 返回当前线程标识符
// Thread.currentThread().getName() 返回当前线程对象
System.out.println(Thread.currentThread().getId() + " " + Thread.currentThread().getName() + " " + i);
}
}
}

2. start()和run()的区别

  1. 启动该线程执行,java虚拟机自动调用这个线程的run方法。结果是,两个线程同时运行:当前线程(调用start()方法)和启动的线程(JVM执行了run方法)。
  2. start()方法来启动线程,真正实现了多线程并行运行。这时无需等待 run 方法体代码执行完毕,可以直接继续执行下面的代码或其他线程代码。
  3. 通过调用 Thread 类的 start()方法来启动一个线程, 这时此线程是处于就绪状态, 并没有运行。
  4. 方法 run()称为线程体,它包含了要执行的这个线程的内容,线程就进入了运行状态,开始运行 run 函数当中的代码。Run方法运行结束,此线程终止,然后 CPU 再调度其它线程。

3. 线程状态(5种)

image-20230316135923199
如图所示:
初始New → 运行RUNNABLE → 等待WAITING(限期/无限期) → 阻塞BLOCKED → 终止TERMINATED

  • JDK5之后,READY+RUNNING 合并为 **RUNNABLE(运行态)**。

4. 线程的常用方法

4.1 Thread构造方法

分配新的 Thread 线程对象:

1
2
3
4
Thread() // 无参构造方法
Thread(String name) // 1参构造方法,参数为线程自定名称
Thread(Runnable target) // 1参构造方法,参数为接口实现类对象
Thread(Runnable target, String name) // 2参构造方法,参数为接口实现类对象 + 线程自定名称

4.2 Thread静态方法

1
2
3
4
5
6
7
8
9
10
11
12
static Thread currentThread() 
返回当前正在执行的线程对象的引用。常用Thread.currentThread().getName()输出线程名称。
static void dumpStack()
将当前线程的堆栈跟踪打印到标准错误流中。
static boolean holdsLock(Object obj)
返回 true如果当前线程拥有指定对象上的锁的监控。
static boolean interrupted()
测试当前线程是否已被中断。
static void sleep(long millis)
当前正在执行的线程休眠(暂停执行)为指定的毫秒数,根据精度和系统定时器和调度的准确性。
static void yield()
给调度程序的一个提示,当前线程愿意得到它当前的处理器的使用。

4.3 Thread成员方法

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
void start() 
导致该线程开始执行;java虚拟机调用这个线程的 run方法。最常用!启动线程!
long getId()
返回此线程的标识符。
String getName()
返回此线程的名称。
int getPriority()
返回此线程的优先级。
Thread.State getState()
返回此线程的状态。
boolean isAlive()
测试这个线程是否还活着。
boolean isDaemon()
如果该线程是守护线程。
boolean isInterrupted()
测试此线程是否已被中断。
void join()
等待该线程死亡。
void setDaemon(boolean on)
标志着该线程是 daemon线程或用户线程。
void setName(String name)
改变该线程的名称等于参数 name。
void setPriority(int newPriority)
更改此线程的优先级。
String toString()
返回此线程的字符串表示形式,包括线程的名称、优先级和线程组。

5. Callable接口

1
2
3
public interface Callable<V> {
public V call() throws Exception;
}

特点:

  • JDK5加入,与Runnable接口类似,实现之后代表一个线程任务;
  • Callable具有泛型返回值,可以声明异常
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 普通方式 - 定义
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class TestCallable {
public static void main(String[] args) {
ExecutorService es = Executors.newFixedThreadPool(3);
ThisTask task = new ThisTask();

es.submit(task);
}
}
class ThisTask implements Callable<Object> {
@Override
public Object call() throws Exception {
for (int i = 1; i <= 50; i++) {
Thread.sleep((int)(Math.random() * 1000));
System.out.println(Thread.currentThread().getName() + ":" + i);
}

return null;
}
}
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
35
36
37
38
39
// 匿名内部类 - 定义
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class TestNonNameThread {
public static void main(String[] args) {

// 匿名内部类 - 创建一个带有返回值的call线程任务
Callable<Object> c = new Callable<Object>() {
@Override
public Object call() throws Exception { // ①允许抛异常
int sum = 0;
for (int i = 0; i <= 100; i++) {
Thread.sleep(1000);
sum += i;
}
return sum; // ②强制返回值
}
};
ExecutorService es = Executors.newFixedThreadPool(3);
es.submit(c);
System.out.println(es.toString());
// 输出:java.util.concurrent.ThreadPoolExecutor@33909752
// [Running, pool size = 1, active threads = 1, queued tasks = 0, completed tasks = 0]


// 匿名内部类 - 创建一个run线程任务
Runnable r = new Runnable() {
@Override
public void run() {
for (int i = 0; i <= 100; i++) {
System.out.println(i);
}
}
};
Thread thread2 = new Thread(r, "线程2");
System.out.println(thread2.toString()); // Thread[线程2,5,main]
}
}

6. Future接口

1
public interface Future<V>

特点:

  • 异步接收 ExecutorService.submit() 所返回的状态结果,当中包含了call()的返回值;
  • 方法: V get() 以阻塞形式等待Future中的异步/并发计算处理结果(call()的返回值)
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
35
36
37
38
39
40
41
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class TestFuture {
public static void main(String[] args) throws InterruptedException, ExecutionException {
ExecutorService es = Executors.newFixedThreadPool(3);
MyCall call = new MyCall();
MyCall2 call2 = new MyCall2();

// 通过submit执行提交的任务,Future接收返回的结果
Future<Integer> f = es.submit(call);
Future<Integer> f2 = es.submit(call2);
System.out.println( f.get() + f2.get()); // 5050
}
}
// 计算1~50的和
class MyCall implements Callable<Integer> {
@Override
public Integer call() throws Exception {
Integer sum = 0;
for (int i = 1; i <= 50; i++) {
sum += i;
}
System.out.println(Thread.currentThread().getName() + ":" + sum);
return sum; // 1275
}
}
// 计算51~100的和
class MyCall2 implements Callable<Integer> {
@Override
public Integer call() throws Exception {
Integer sum = 0;
for (int i = 51; i <= 100; i++) {
sum += i;
}
System.out.println(Thread.currentThread().getName() + ":" + sum);
return sum; // 3775
}
}

01-线程
https://janycode.github.io/2016/04/28/02_编程语言/01_Java/01_JavaSE/05_并发和锁/01-线程/
作者
Jerry(姜源)
发布于
2016年4月28日
许可协议