JUC多线程

Posted by Chenyawei on 2019-12-15
Words 3.9k and Reading Time 20 Minutes
Viewed Times

一.线程—操作—资源类. 2.高内聚—低耦合

线程操作资源类,并保证高内聚、低耦合。

根据下面的demo分析什么是线程操作资源类,并保证高内聚、低耦合。

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

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

//Ticket 为售票的操作,内部有30张票待出售,为资源类,
//class Ticket implements Runnable{ 如果在资源类上实现线程接口,资源和线程就耦合到一块了。
class Ticket{
private int number = 30; //票数

private Lock lock = new ReentrantLock();

public void sail(){
lock.lock(); // block until condition holds
try {
if(number > 0) {
System.out.println(Thread.currentThread().getName() + "出售了第" + number-- + "张票,还剩余" + number + "张票。");
}
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
}

public class ThreadDemo1 {

public static void main(String[] args) { //main方法自己带资源对外提供服务
Ticket ticket = new Ticket();


//不要在资源类上实现Runnble,而是在创建线程的时候来操作。为线程与资源类的低耦合
new Thread(new Runnable() { //匿名内部类方式
@Override
public void run() {
for(int i = 0; i < 40; i++){
ticket.sail(); //线程操作资源类
}
}
}, "A").start();

new Thread(new Runnable() {
@Override
public void run() {
for(int i = 0; i < 40; i++){
ticket.sail(); //线程操作资源类
}
}
},"B").start();

new Thread(new Runnable() {
@Override
public void run() {
for(int i = 0; i < 40; i++){
ticket.sail(); //线程操作资源类
}
}
}, "C").start();

//Lambda语法方式,写法(开发中推荐使用这种简洁的代码)
new Thread(() -> {for(int i = 0; i < 40; i++){ ticket.sail();} },"AA").start();
new Thread(() -> {for(int i = 0; i < 40; i++){ ticket.sail();} },"BB").start();
new Thread(() -> {for(int i = 0; i < 40; i++){ ticket.sail();} },"CC").start();
}
}


/**
* 1. implements 来实现 (效率低,非低耦合,不推荐)
* 2. 匿名内部类 (推荐)
* 3. Lambda方式 (非常推荐)
**/

二. Callbale 与 Runnable 两个接口的区别

1. Callbale 与 Runnable 两个接口的区别

Runnable的静态方法run()没有返回值。

Callbale的静态方法call()有泛型返回值,并且有throws抛出异常

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class MyFoo implements Runnable
{
@Override
public void run() {

}
}

class Myfoo2 implements Callable<Integer>
{
@Override
public Integer call() throws Exception {
return null;
}
}

2.Callbale应用实例:与FutureTask类配合使用

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.learnjava.JUC;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

class MyCallable implements Callable<Integer>
{
@Override
public Integer call() throws Exception {
System.out.println(Thread.currentThread().getName() + "线程的call......");
return 200;
}
}

/**
* Cabllable
* @Author: chenyawei
* @Date: 2019-12-14 20:56
* @Version: 1.0
*/
public class ThreadDemo2 {

public static void main(String[] args) throws ExecutionException, InterruptedException {

FutureTask<Integer> futureTask = new FutureTask<Integer>(new MyCallable());
new Thread(futureTask,"AA").start();

//Lambda实现方式
FutureTask<Integer> futureTask1 = new FutureTask<Integer>(() -> {
System.out.println(Thread.currentThread().getName() + "线程的call......");
return 300;
});
new Thread(futureTask1,"BB").start();
System.out.println("futureTask1.get() = "+futureTask1.get());
}
}

在主线程中需要执行比较耗时的操作时,但又不想阻塞主线程时,可以把这些作业交给Future对象在后台完成,当主线程将来需要时,就可以通过Future对象获得后台作业的计算或者执行状态。

一般FutureTask类多用于耗时计算,主线程可以在完成自己的任务后,再去获取结果。

仅在计算完成时才能检索结果;如果计算尚未完成,则阻塞get方法。一旦计算完成,就不能再重新开始或取消计算。get方法获取结果只有在计算完成时获取,否则会一直阻塞直到任务转入完成状态,然后会返回结果或者抛出异常。所有get方法一般放在最后。

三. notify和wait

wait使用前一定要有同步锁synchronized,它们是一套全家福,且wait() 与 notify(), 或 wait() 与 notifyAll(),必须成对使用,

版本1 Demo:

有两个线程,实现对初始值为0的一个变量操作,一个线程对变量加一,另一个线程对变量减一,循环4轮

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

//资源类
class ShareData{
private int number = 0;
//消费者
public synchronized void increment() throws InterruptedException {
if(number != 0){
this.wait();
}
++number;
System.out.println(Thread.currentThread().getName() + "\t" + number);
this.notifyAll();
}
//消费者模式
public synchronized void decrement() throws InterruptedException {
if(number == 0){
this.wait();
}
--number;
System.out.println(Thread.currentThread().getName() + "\t" + number);
this.notifyAll();
}
}

/**
*
*题目:有两个线程,实现对初始值为0的一个变量操作,一个线程对变量加一,另一个线程对变量减一,循环4轮
* @Author: chenyawei
* @Date: 2019-12-14 20:56
* @Version: 1.0
*/
public class ThreadDemo3 {
public static void main(String[] args)
{
ShareData shareData = new ShareData();

new Thread(() -> {
for (int i = 0; i < 10; i++){
try {
shareData.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"AA").start();

new Thread(() -> {
for (int i = 0; i < 10; i++){
try {
shareData.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"BB").start();
}
}

两个执行结果为4次轮换:
AA 1
BB 0
AA 1
BB 0

01轮换执行,看这没有问题

版本2 Demo:

有2个线程改为4个线程,实现上面的功能,会出现运行结果为2的情况

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
91
92
93
94
package com.learnjava.JUC;

//资源类
class ShareData{
private int number = 0;
//消费者
public synchronized void increment() throws InterruptedException {
if(number != 0){
this.wait();
}
++number;
System.out.println(Thread.currentThread().getName() + "\t" + number);
this.notifyAll();
}
//消费者模式
public synchronized void decrement() throws InterruptedException {
if(number == 0){
this.wait();
}
--number;
System.out.println(Thread.currentThread().getName() + "\t" + number);
this.notifyAll();
}
}

public class ThreadDemo3 {
public static void main(String[] args)
{
ShareData shareData = new ShareData();

new Thread(() -> {
for (int i = 0; i < 4; i++){
try {
Thread.sleep(200); //睡眠0.2秒模拟网络延迟
shareData.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"AA").start();

new Thread(() -> {
for (int i = 0; i < 4; i++){
try {
Thread.sleep(300); //睡眠模拟网络延迟
shareData.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"BB").start();

new Thread(() -> {
for (int i = 0; i < 4; i++){
try {
Thread.sleep(400); //睡眠模拟网络延迟
shareData.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"CC").start();

new Thread(() -> {
for (int i = 0; i < 4; i++){
try {
Thread.sleep(500); //睡眠模拟网络延迟
shareData.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"DD").start();
}
}


4个执行结果为4次轮换:发现结果出现了 2 的情况,答案错误了。
AA 1
BB 0
AA 1
DD 0
CC 1
BB 0
AA 1
BB 0
CC 1
AA 2
DD 1
BB 0
CC 1
DD 0
CC 1
DD 0

这种情况即为线程的虚假唤醒。

image-20191215171843863

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
API Note:
The recommended approach to waiting is to check the condition being awaited in a while loop around the call to wait, as shown in the example below. Among other things, this approach avoids problems that can be caused by spurious wakeups.

synchronized (obj) {
while (<condition does not hold> and <timeout not exceeded>) {
long timeoutMillis = ... ; // recompute timeout values
int nanos = ... ;
obj.wait(timeoutMillis, nanos);
}
... // Perform action appropriate to condition or timeout
}

Parameters:
timeoutMillis - the maximum time to wait, in milliseconds
nanos - additional time, in nanoseconds, in the range range 0-999999 inclusive

上面是JDK 的 API 文档提示,多线程变量里面不能用 if 判断 只能用while 循环判断, 所有的拉回来重新过安检。问题就可以解决了。

1
2
3
4
5
6
7
if(number != 0){
this.wait();
}
修改为:
while (number != 0){
this.wait();
}

四. lock

Lock api 文档:lock 必须 与 Condition接口配套使用

1
2
3
4
5
6
7
8
9
10
11
public interface Lock
Lock implementations provide more extensive locking operations than can be obtained using synchronized methods and statements. They allow more flexible structuring, may have quite different properties, and may support multiple associated Condition objects.

公共接口锁
与使用同步方法和语句相比,锁实现提供了更广泛的锁操作。 它们允许更灵活的结构,可以具有完全不同的属性,并且可以支持多个关联的Condition对象。

public interface Condition
Condition factors out the Object monitor methods (wait, notify and notifyAll) into distinct objects to give the effect of having multiple wait-sets per object, by combining them with the use of arbitrary Lock implementations. Where a Lock replaces the use of synchronized methods and statements, a Condition replaces the use of the Object monitor methods.

Condition对象公共接口条件
条件将对象监视方法(waitnotifynotifyAll)分解为不同的对象,从而通过与任意Lock实现结合使用,从而使每个对象具有多个等待集。 如果Lock替换了同步方法和语句的使用,而Condition替换了Object监视器方法的使用。
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
//资源类
class ShareData{
private int number = 0;

private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();

//生产者
public void increment() throws InterruptedException{
lock.lock();
try {
while (number != 0){
condition.await(); //使用condition的await()方法代替 wait()
}
++number;
System.out.println(Thread.currentThread().getName() + "\t" + number);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}

//消费者模式
public void decrement() throws InterruptedException{
lock.lock();
try {
while (number == 0){
condition.await();
}
--number;
System.out.println(Thread.currentThread().getName() + "\t" + number);
}catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}

}

六.线程8锁 synchronized

总述:

资源类里面有多个synchronized方法的时候,某一时刻只要有一个线程调用synchronized方法了,其他的线程都只能等待,换句话说,某一时刻内,只允许一个线程访问这些synchronized方法。

锁是当前对象this,被锁定后,其他线程都不能进入到当前对象的其他的synchronized方法了。所以静态方法,根几个对象没有关系。也可以理解为锁的是模版class。

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

class Phone{
public synchronized void getIOS() throws Exception{
System.out.println("***getIOS");
}
public synchronized void getAndroid(){
System.out.println("***getAndriod");
}
}

/**
*
* 题目 : 线程8 锁
* @Author: chenyawei
* @Date: 2019-12-14 20:56
* @Version: 1.0
*/
public class ThreadDemo4 {

public static void main(String[] args)
{

Phone phone = new Phone();

new Thread(() -> {
try {
phone.getIOS();
} catch (Exception e) {
e.printStackTrace();
}
},"AA").start();

new Thread(() -> {
try {
phone.getAndroid();
} catch (Exception e) {
e.printStackTrace();
}
},"BB").start();

}
}

运行结果:一般都会按线程上下顺序执行

1
2
***getIOS
***getAndriod

2. 让getIOS()睡 4 秒 ,打印顺序是?

1
2
3
4
5
6
7
8
9
class Phone{
public synchronized void getIOS() throws Exception{
TimeUnit.SECONDS.sleep(4);
System.out.println("***getIOS");
}
public synchronized void getAndroid(){
System.out.println("***getAndriod");
}
}

打印结果: 结果和标准顺序一样

1
2
***getIOS
***getAndriod

3. 新增普通方法 getHello() ,让getIOS()睡 4秒 , 查看打印顺序

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
class Phone {
public synchronized void getIOS() throws Exception {
TimeUnit.SECONDS.sleep(4);
System.out.println("***getIOS");
}

public synchronized void getAndroid() {
System.out.println("***getAndriod");
}

public void getHello() {
System.out.println("***getHello");
}
}

public class ThreadDemo4 {

public static void main(String[] args)
{
Phone phone = new Phone();

new Thread(() -> {
try {
phone.getIOS();
} catch (Exception e) {
e.printStackTrace();
}
},"AA").start();

new Thread(() -> {
try {
// phone.getAndroid();
phone.getHello();
} catch (Exception e) {
e.printStackTrace();
}
},"BB").start();

}
}

打印结果: 顺序有变,普通方法在前面了

1
2
***getHello
***getIOS

4.有两部手机(有两个资源类)就是两个对象,看打印顺序

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

import java.util.concurrent.TimeUnit;

class Phone {
public synchronized void getIOS() throws Exception {
TimeUnit.SECONDS.sleep(4);
System.out.println("***getIOS");
}

public synchronized void getAndroid() {
System.out.println("***getAndriod");
}

public void getHello() {
System.out.println("***getHello");
}
}

public class ThreadDemo4 {

public static void main(String[] args)
{

Phone phone = new Phone();
Phone phone2 = new Phone();

new Thread(() -> {
try {
phone.getIOS();
} catch (Exception e) {
e.printStackTrace();
}
},"AA").start();

new Thread(() -> {
try {
phone2.getAndroid();
} catch (Exception e) {
e.printStackTrace();
}
},"BB").start();

}
}

运行结果:

1
2
***getAndriod
***getIOS

5.两个静态方法,一部手机,打印顺序

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

import java.util.concurrent.TimeUnit;

class Phone {
public static synchronized void getIOS() throws Exception {
TimeUnit.SECONDS.sleep(4);
System.out.println("***getIOS");
}

public static synchronized void getAndroid() {
System.out.println("***getAndriod");
}

public void getHello() {
System.out.println("***getHello");
}
}
/**
*
* 题目 : 线程8 锁
* @Author: chenyawei
* @Date: 2019-12-14 20:56
* @Version: 1.0
*/
public class ThreadDemo4 {

public static void main(String[] args)
{

Phone phone = new Phone();
new Thread(() -> {
try {
phone.getIOS();
} catch (Exception e) {
e.printStackTrace();
}
},"AA").start();

new Thread(() -> {
try {
phone.getAndroid();
} catch (Exception e) {
e.printStackTrace();
}
},"BB").start();

}
}

运行结果:

1
2
***getIOS
***getAndriod

6.两个静态方法,两部手机,打印顺序

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

import java.util.concurrent.TimeUnit;

class Phone {
public static synchronized void getIOS() throws Exception {
TimeUnit.SECONDS.sleep(4);
System.out.println("***getIOS");
}

public static synchronized void getAndroid() {
System.out.println("***getAndriod");
}

public void getHello() {
System.out.println("***getHello");
}
}
/**
*
* 题目 : 线程8 锁
* @Author: chenyawei
* @Date: 2019-12-14 20:56
* @Version: 1.0
*/
public class ThreadDemo4 {

public static void main(String[] args)
{

Phone phone = new Phone();
Phone phone2 = new Phone();

new Thread(() -> {
try {
phone.getIOS();
} catch (Exception e) {
e.printStackTrace();
}
},"AA").start();

new Thread(() -> {
try {
phone2.getAndroid();
} catch (Exception e) {
e.printStackTrace();
}
},"BB").start();

}
}

运行结果:

1
2
***getIOS
***getAndriod

7.一个静态方法,一个普通方法,一部手机,打印顺序

运行结果:

1
2
***getAndriod
***getIOS

8.一个静态方法,一个普通方法,两部手机,打印顺序

运行结果:

1
2
***getAndriod
***getIOS

七. Lock 之 Condition

Lock 优于同步锁synchronized的点为,可以指定唤醒的线程。没有指定的情况下和synchronized一样都是疯抢模式。

Demo:

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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
package com.learnjava.JUC;


import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

class ShareResource{
private int flag = 1; // 1-A, 2-B, 3-C
private Lock lock = new ReentrantLock();
private Condition condition1 = lock.newCondition();
private Condition condition2 = lock.newCondition();
private Condition condition3 = lock.newCondition();

public void print5(int totalLoop){
lock.lock();
try{
//判断
while (flag != 1){
condition1.await();
}
//干活
for(int i = 1; i <= 5; i++){
System.out.println(Thread.currentThread().getName() + "\t" + i + "\ttotalLoop: " + totalLoop);
}
//通知+唤醒
flag = 2;
condition2.signal();
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}

public void print10(int totalLoop){
lock.lock();
try{
//判断
while (flag != 2){
condition2.await();
}
//干活
for(int i = 1; i <= 10; i++){
System.out.println(Thread.currentThread().getName() + "\t" + i + "\ttotalLoop: " + totalLoop);
}
//通知+唤醒
flag = 3;
condition3.signal();
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}

public void print15(int totalLoop){
lock.lock();
try{
//判断
while (flag != 3){
condition3.await();
}
//干活
for(int i = 1; i <= 15; i++){
System.out.println(Thread.currentThread().getName() + "\t" + i + "\ttotalLoop: " + totalLoop);
}
//通知+唤醒
flag = 1;
condition1.signal();
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
}

/**
* 题目:有ABC三个线程,A线程打印5次,B线程打印10次,C线程打印15次,然后,在同样的顺序打印第2轮,总共打印10轮
*
* @Author: chenyawei
* @Date: 2019-12-15 19:24
*/
public class ThreadDemo5
{
public static void main(String[] args)
{
ShareResource shareResource = new ShareResource();

new Thread(() -> {
for (int i = 1; i <= 10; i++){
shareResource.print5(i);
}
},"AA").start();

new Thread(() -> {
for (int i = 1; i <= 10; i++){
shareResource.print10(i);
}
},"BB").start();

new Thread(() -> {
for (int i = 1; i <= 10; i++){
shareResource.print15(i);
}
},"CC").start();
}
}

八.lock之读写锁ReentrantReadWriteLock

ReentrantReadWriteLock 的使用demo:

wrlock.writeLock().lock(); wrlock.readLock().lock();

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

import java.util.concurrent.locks.ReentrantReadWriteLock;

class MyReadWrite{
private Object object;
private ReentrantReadWriteLock wrlock = new ReentrantReadWriteLock();

public void write(Object obj){
wrlock.writeLock().lock();
try {
this.object = obj;
System.out.println(Thread.currentThread().getName() + "\t" + object);
}catch (Exception e){
e.printStackTrace();
}finally {
wrlock.writeLock().unlock();
}
}

public void read(){
wrlock.readLock().lock();
try {
System.out.println(Thread.currentThread().getName() + "\t" + object);
}catch (Exception e){
e.printStackTrace();
}finally {
wrlock.readLock().unlock();
}
}
}

/**
* 题目: 100个线程读取,1个线程写
* @Author: chenyawei
* @Date: 2019-12-15 20:08
*/
public class TreadDemo6 {

public static void main(String[] args) throws InterruptedException {

MyReadWrite myReadWrite = new MyReadWrite();

new Thread(() -> {
myReadWrite.write("writie......");
},"myReadWrite").start();

Thread.sleep(100); //防止还没有写的时候就读

for (int i = 1; i <= 100; i++){
new Thread(() -> {
myReadWrite.read();
},String.valueOf(i)).start();
}

}
}

九.线程池 Executor

推送使用Executors工具类创建ExecutorService对象

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

import java.util.Random;
import java.util.concurrent.*;

/**
* @Author: chenyawei
* @Date: 2019-12-15 21:03
*/
public class ThreadDemo7
{
public static void main(String[] args)
{
//threadPool();
ScheduledExecutorService executorService = Executors.newScheduledThreadPool(5);
ScheduledFuture<Integer> future = null;
try {
for (int i = 1; i <= 20; i++){
future = executorService.schedule(() -> {
System.out.println(Thread.currentThread().getName());
return new Random().nextInt(50);
},2,TimeUnit.SECONDS);
System.out.println("**" + future.get());
}
}catch (Exception e){
e.printStackTrace();
}finally {
executorService.shutdown();
}
}

private static void threadPool() {
ExecutorService threadPool = Executors.newFixedThreadPool(5);
ExecutorService threadPool2 = Executors.newSingleThreadExecutor(); //一直保持一个线程
ExecutorService threadPool3 = Executors.newCachedThreadPool(); //根据需要程序自己启动线程数

Future<Integer> result = null;
try{
for (int i=1; i <= 20; i++){

// result = threadPool.submit(new Callable<Integer>() {
// @Override
// public Integer call() throws Exception {
// System.out.print(Thread.currentThread().getName());
// return new Random().nextInt(50);
// }
// });

//Lambda语法
result = threadPool3.submit(() -> {
System.out.print(Thread.currentThread().getName());
return new Random().nextInt(50);
});
System.out.println("**" + result.get());
}

}catch (Exception e){
e.printStackTrace();
}finally {
threadPool3.shutdown();
}
}
}

notice

欢迎访问 chenyawei 的博客, 若有问题或者有好的建议欢迎留言,笔者看到之后会及时回复。 评论点赞需要github账号登录,如果没有账号的话请点击 github 注册, 谢谢 !

If you like this blog or find it useful for you, you are welcome to comment on it. You are also welcome to share this blog, so that more people can participate in it. If the images used in the blog infringe your copyright, please contact the author to delete them. Thank you !