网络编程

实现多线程的三种方式

(1)继承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
package com.cskaoyan;


public class Demo {

public static void main(String[] args) {

// 启动2个线程
for (int i = 0; i < 2; i++) {
new MyThread().start();
}

}
}


class MyThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(getName() + "打印了" + i);
}
}
}

(2)实现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
package com.cskaoyan;


public class Demo {

public static void main(String[] args) {

MyThread mt = new MyThread();
// 启动2个线程
for (int i = 0; i < 2; i++) {
new Thread(mt).start();
}

}
}


class MyThread implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + "打印了" + i);
}
}
}

(3)实现Callable接口,重写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
package com.cskaoyan;


import javax.swing.*;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

public class Demo {
public static void main(String[] args) {

// 线程A
Thread t = new Thread(new FutureTask(new A()));
t.start();

// 主线程
System.out.println("main线程...");

}
}

// 线程A
class A implements Callable {

@Override
public Object call() throws Exception {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + "->" + i);
}
return null;
}

}

多线程环境下共享数据安全问题

确保数据安全的两种方式

一个java对象相当于一把锁

同步代码块

1
2
3
synchronized (锁对象) {

}

同步方法

1
2
3
public synchronized void method() {

}

生产者与消费者模式

两个线程交替打印

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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
package com.cskaoyan;

public class Demo {

public static void main(String[] args) {

// 实现两个线程交替打印
Signal s = new Signal();
// 线程A
new Thread(new A(s)).start();
// 线程B
new Thread(new B(s)).start();

}
}


// 信号
class Signal {
boolean flag = true;
}


// 线程A
class A implements Runnable {

Signal s;

@Override
public void run() {
printA();
}

public A(Signal s) {
this.s = s;
}

public void printA(){
while (true) {
synchronized (s) {
if(s.flag){
System.out.println("A");
s.flag = false;
// 通知B线程打印
s.notify();
}else {
try {
s.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}

// 线程B
class B implements Runnable {

Signal s;

@Override
public void run() {
printB();
}

public B(Signal s) {
this.s = s;
}

public void printB(){
while (true) {
synchronized (s) {
if(!s.flag){
System.out.println("B");
s.flag = true;
// 通知A线程打印
s.notify();
}else {
try {
s.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}

死锁

死锁

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
package com.cskaoyan;
import java.util.Random;

public class Demo {
public static void main(String[] args) {

Lock lock = new Lock();

new Thread(new MyThread1(lock)).start();
new Thread(new MyThread2(lock)).start();

}
}

// 共享资源
class Lock {
// 创建两把锁
Object o1 = new Object();
Object o2 = new Object();
}


class MyThread1 implements Runnable {

Lock lock;

@Override
public void run() {
test();
}

public MyThread1(Lock lock) {
this.lock = lock;
}

public void test(){
while (true){
synchronized (lock.o1) {
synchronized (lock.o2) {
System.out.println(Thread.currentThread().getName() + "进厕所...");
}
}
}
}
}


class MyThread2 implements Runnable {

Lock lock;

@Override
public void run() {
test();
}

public MyThread2(Lock lock) {
this.lock = lock;
}

public void test(){
while (true){
synchronized (lock.o2) {
synchronized (lock.o1) {
System.out.println(Thread.currentThread().getName() + "进厕所...");
}
}
}
}
}

如何避免死锁?

1
2
3
4
5
synchronized (lock.o1) {
synchronized (lock.o2) {
code...
}
}

确保每个线程加锁的顺序一致,新增一把锁

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 线程1
synchronized (lock.o3){
synchronized (lock.o2) {
synchronized (lock.o1) {
code...
}
}
}

// 线程2
synchronized (lock.o3){
synchronized (lock.o1) {
synchronized (lock.o2) {
code...
}
}
}

线程间通信

通过wait以及notify实现线程间通信

线程A打印100以内的所有奇数

线程B打印100以内的所有偶数

示例代码如下

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
76
77
78
79
80
81
82
83
84
85
86
87
public class Demo {
public static void main(String[] args) {
// 共享资源
Signal s = new Signal();
// A线程
new Thread(new A(s)).start();
// B线程
new Thread(new B(s)).start();

}
}

// 共享资源
class Signal {
boolean flag = true;
int i = 1;
}


// 线程A
class A implements Runnable {

Signal s;

public A(Signal s) {
this.s = s;
}

@Override
public void run() {
printOdd();
}


public void printOdd() {
while (s.i <= 100) {
synchronized (s) {
if (s.flag) {
System.out.println("奇数线程:" + s.i++);
s.flag = false;
s.notify();
} else {
try {
s.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}


// 线程B
class B implements Runnable {

Signal s;

public B(Signal s) {
this.s = s;
}

@Override
public void run() {
printEven();
}


public void printEven() {
while (s.i <= 100) {
synchronized (s) {
if (!s.flag) {
System.out.println("偶数线程:" + s.i++);
s.flag = true;
s.notify();
} else {
try {
s.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}

线程的生命周期

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
public class Demo {
public static void main(String[] args) {

// 线程A
Thread t = new Thread(new A());
t.start();

try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}

System.out.println("main线程");
}
}

// 线程A
class A implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

线程池

(1)线程池newCachedThreadPool

动态线程池

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
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Demo {
public static void main(String[] args) {

// 创建线程池
ExecutorService pool = Executors.newCachedThreadPool();
// 提交30个线程到线程池
Thread t = new Thread(new A());
for (int i = 0; i < 30; i++) {
pool.submit(t);
}
System.out.println("main线程");
// 任务完成后, 关闭线程池
pool.shutdown();

}
}

// 负责打印1到10线程
class A implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + "->" + i);
}
}
}

(2)线程池newFixedThreadPool

数量固定的线程池

1
2
// 创建线程池
ExecutorService pool = Executors.newFixedThreadPool(10);

(3)线程池newSingleThreadExecutor

1
2
// 创建线程池
ExecutorService pool = Executors.newSingleThreadExecutor();

如果线程有返回值,那么如何做呢?

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
package com.cskaoyan;


import java.util.concurrent.*;

public class Demo {
public static void main(String[] args) {

// 创建FutureTask对象
FutureTask futureTask = new FutureTask(new A());
// 线程A
Thread t = new Thread(futureTask);
t.start();
try {
// 获取返回结果
String res = ((String) futureTask.get());
System.out.println(res);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
System.out.println("main线程");

}
}

// 线程A
class A implements Callable {

@Override
public Object call() throws Exception {
System.out.println(Thread.currentThread().getName());
return "线程A";
}

}

示例代码如下

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
package com.cskaoyan;


import java.util.concurrent.*;

public class Demo {
public static void main(String[] args) {

// 线程池
ExecutorService pool = Executors.newFixedThreadPool(10);
// A类对象
A task = new A();
// 获取返回值
Future future1 = pool.submit(task);
Future future2 = pool.submit(task);
// 关闭线程池
pool.shutdown();
try {
// 获取返回结果
String res1 = ((String) future1.get());
String res2 = ((String) future2.get());
System.out.println(res1);
System.out.println(res2);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
System.out.println("main线程");
}
}

// 任务
class A implements Callable {

@Override
public Object call() throws Exception {
System.out.println(Thread.currentThread().getName());
return "分支线程...";
}

}

定时任务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import java.util.Timer;
import java.util.TimerTask;

public class Demo {
public static void main(String[] args) {

// 创建定时器
Timer timer = new Timer();
timer.schedule(new MyTask(), 5000);
System.out.println("main");

// 取消定时器
// timer.cancel();
}
}

class MyTask extends TimerTask {
@Override
public void run() {
System.out.println("定时任务...");
}
}

网络编程
http://cxycsx.vip/2023/08/31/其他/网络编程/
作者
程序员陈师兄
发布于
2023年8月31日
许可协议