Java-015-多线程

Java线程的概念

多线程程序包含两条或两条以上并发运行的部分.程序中每个这样的部分都叫一个线程(thread),每个线程都有独立的执行路径。因此,多线程是多任务处理的一种特殊形式.

一句话总结进程和线程的关系: 进程是线程的容器!

进程的主线程

主线程的重要性体现在:

  • 它是产生其他子线程的线程
  • 通常它必须最后完成执行,因为它执行各种关闭动作

主线程是运行程序时候自动创建的, 但是其也是一个Thread类的实例对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class CurrentThreadDemo {
public static void main(String args[]) {
Thread t = Thread.currentThread();
System.out.println("Current thread: " + t);
// change the name of the thread
t.setName("My Thread");
System.out.println("After name change: " + t);
try {
for (int n = 5; n > 0; n--) {
System.out.println(n);
Thread.sleep(1000);
}
} catch (InterruptedException e) {
System.out.println("Main thread interrupted");
}
}
}

创建线程

继承Thread

  • 我们可以通过继承Thread类, 然后Override run()方法, 然后创建该类的实例来创建除了主线程之外的其他线程, 并且在run()方法中赋予属于这个线程的代码逻辑, 这个run()方法是新线程的入口.
  • 这个新建的Thread类的子类, 会继承Thread类的一个方法 – start(), 当我们调用start()方法时候会自动生成一个线程, 然后调用run()方法执行线程的逻辑.
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
// Create a second thread by extending Thread
class NewThread extends Thread {
NewThread() {
// Create a new, second thread
super("Demo Thread");
System.out.println("Child thread: " + this);
start(); // Start the thread
}

// This is the entry point for the second thread.
public void run() {
try {
for (int i = 5; i > 0; i--) {
System.out.println("Child Thread: " + i);
Thread.sleep(500);
}
} catch (InterruptedException e) {
System.out.println("Child interrupted.");
}
System.out.println("Exiting child thread.");
}
}

public class Demo {
public static void main(String args[]) {
new NewThread(); // create a new thread
try {
for (int i = 5; i > 0; i--) {
System.out.println("Main Thread: " + i);
Thread.sleep(1000);
}
} catch (InterruptedException e) {
System.out.println("Main thread interrupted.");
}
System.out.println("Main thread exiting.");
}
}

实现 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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// Create multiple threads.
class NewThread implements Runnable {
String name; // name of thread
Thread t;

NewThread(String threadname) {
name = threadname;
t = new Thread(this, name);
System.out.println("New thread: " + t);
t.start(); // Start the thread
}

// This is the entry point for thread.
public void run() {
try {
for (int i = 5; i > 0; i--) {
System.out.println(name + ": " + i);
Thread.sleep(1000);
}
} catch (InterruptedException e) {
System.out.println(name + "Interrupted");
}
System.out.println(name + " exiting.");
}
}

public class Demo {
public static void main(String args[]) {
new NewThread("One"); // start threads
new NewThread("Two");
new NewThread("Three");
try {
// wait for other threads to end
Thread.sleep(10000);
} catch (InterruptedException e) {
System.out.println("Main thread Interrupted");
}
System.out.println("Main thread exiting.");
}
}

练习

使用多线程技术, 写一个程序, 创建3个线程, 然后完成工作:

  • 主线程一直循环输出从1 开始的数字, 一直到100;
  • 创建的2个子线程: 子线程A输出大写字母从A到Z, 子线程B输出小写字母从a到z
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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
package com.repeat;


public class Work01 {
public static void main(String[] args) throws InterruptedException {
Thread t = Thread.currentThread();
t.setName("main thread");

MyThread t2 = new MyThread("aaa");
MyThread2 t3 = new MyThread2("bbb");

t2.start();
t3.start();

for (int i = 1; i <= 100; i++) {
System.out.println(t.getName() + " running " + i);
Thread.sleep(50);
}
}
}

class MyThread extends Thread{
private Thread t;
private String name;

public MyThread(String name) {
this.name = name;
}

@Override
public void run() {
try {
for (int i = 65; i < 65+26; i++) {
char a = (char) i;
System.out.println(name+ " running " + a);
Thread.sleep(50);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}

public void start(){
t = new Thread (this, name);
t.start ();
}
}

class MyThread2 implements Runnable{
private Thread t;
private String name;

public MyThread2(String name) {
this.name = name;
}

@Override
public void run() {
try {
for (int i = 97; i < 97 + 26; i++) {
char a = (char) i;
System.out.println(name+ " running " + a);
Thread.sleep(50);
}
} catch (InterruptedException e) {
e.printStackTrace();
}

}

public void start(){
t = new Thread (this, name);
t.start ();
}
}

我们的任务是: 在命令行模拟类似的逻辑:

  • 程序运行之后, 会接收用户输入的字符串, 用户输入回车之后, 把这行字符串写入到一个新的文件中,命名为数字序号 (1.txt, 2.txt, 3.txt)… (回顾一下之前IO的课程中, 对文件写入的操作)
  • 用户输入回车之后, 重新等待用户输入字符串, 并且循环执行 1 中的逻辑
  • 要求是敲下回车之后, 不能有卡顿的情况, 也就是, 写入文件必须在子线程中完成
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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
package com.repeat;

import java.io.*;
import java.util.Scanner;

public class Work02 {
public static void main(String[] args) throws IOException {

while (true){
// 获取输入
String input = getInput();
// 新开线程,写入文件
new MyFileIoThread( input ).start();

}
}

public static String getInput(){
Scanner sc = new Scanner(System.in);
String str = sc.next();
return str;
}
}

class MyFileIoThread extends Thread{
public static int count = 1;
private String content;

public MyFileIoThread(String content) {
this.content = content;
MyFileIoThread.count++;
System.out.println(MyFileIoThread.count);
}

@Override
public void run() {
FileOutputStream output = null;
try {
String fileName = MyFileIoThread.count + ".txt";
output = new FileOutputStream("day015Thread/res/" + fileName);
OutputStreamWriter writer = new OutputStreamWriter(output,"UTF-8");
PrintWriter printWriter = new PrintWriter(writer);

// 模拟写入文件慢的操作
Thread.sleep(500);
System.out.println(" file: " + fileName + " 写入成功");

printWriter.write(content);
printWriter.close();
output.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

参考阅读资料

可以慢慢看, 或者简单过一遍, 然后脑子留个概念. 等之后有经验和需求的时候反复回来咀嚼

大致了解下一些应用场景, 如果不理解也没关系, 慢慢等你有需求被逼无奈就会懂了

一个不错的Java多线程面试相关的题目总结, 可以准备面试时候大致过一遍, 有些内容可能是因为需要用于面试中题目原因, 忽略很多不同概念的联系和有些概念不是特别准确, 但是准备面试后可以看一下. 学习还是需要训练中慢慢体会

Java面试题之多线程.md)