0%

小范围排序、有序数组合并、重复值判断、三色排序问题、有序矩阵查找、最短子数组、相邻两数最大差值

Read more »

注解相当于一种标记,在程序中加了注解就等于为程序打上了某种标记

Read more »

1. 多线程基础

1.1. 线程与进程(彩蛋链接)

  • 进程:是一个正在执行中的程序
  • 线程:是进程的一个独立的控制单元,程序的执行路径
  • 举例:Java VM main线程
  • 扩展:Java VM 的垃圾回收线程

1.2. 线程的几个状态

线程的几个状态

1.3. 对线程对象和名称的操作

  • Thread.currentThread() 获取对象
  • getName() 获取当前线程线程名称
  • 设置线程名称 setName() 或者通过构造函数

1.4. 售票问题

情景:多个窗口同时出售火车票,总票数100张

解决办法

  • 利用static
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.leeeyou.ticket;

/**
* 售票问题展示
*/
public class SaleTicketWithProblem {
public static void main(String[] args) {
Ticket t1 = new Ticket();
Ticket t2 = new Ticket();
Ticket t3 = new Ticket();
Ticket t4 = new Ticket();

t1.start();
t2.start();
t3.start();
t4.start();
}
}

class Ticket extends Thread {
private volatile static int ticket = 50;//总票数
private boolean flag = true;

@Override
public void run() {
while (flag) {
if (ticket > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":" + ticket + " ");
ticket--;
} else {
System.out.println(Thread.currentThread().getName() + ": no ticket");
flag = false;
}
}
}

}
  • 实现Runable接口
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
package com.leeeyou.ticket;

/**
* 售票问题展示
*/
public class SaleTicketWithProblem2 {
public static void main(String[] args) {
Ticket2 t = new Ticket2();

Thread t1 = new Thread(t);
Thread t2 = new Thread(t);
Thread t3 = new Thread(t);
Thread t4 = new Thread(t);

t1.start();
t2.start();
t3.start();
t4.start();
}

}

class Ticket2 implements Runnable {
public int ticket = 50;//总票数
private boolean flag = true;

@Override
public void run() {
while (flag) {
if (ticket > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "...." + ticket--);
} else {
flag = false;
System.out.println(Thread.currentThread().getName() + ": no ticket");
}
}
}

}

结果如下所示,出现了0,-1,-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
Thread-0:50    
Thread-1:49
Thread-2:49
Thread-3:47
Thread-3:46
Thread-2:46
Thread-1:44
Thread-0:44
Thread-3:42
Thread-2:41
Thread-1:40
Thread-0:39
Thread-3:38
Thread-2:37
Thread-1:36
Thread-0:36
Thread-2:34
Thread-3:33
Thread-1:32
Thread-0:32
Thread-2:30
Thread-3:29
Thread-1:28
Thread-0:27
Thread-3:26
Thread-2:26
Thread-1:24
Thread-0:23
Thread-3:22
Thread-1:22
Thread-2:22
Thread-0:19
Thread-3:18
Thread-2:17
Thread-1:16
Thread-0:15
Thread-3:14
Thread-2:13
Thread-1:12
Thread-0:11
Thread-3:10
Thread-2:9
Thread-1:8
Thread-0:7
Thread-2:6
Thread-3:6
Thread-1:4
Thread-0:3
Thread-3:2
Thread-2:2
Thread-2: no ticket
Thread-1:0
Thread-1: no ticket
Thread-0:-1
Thread-0: no ticket
Thread-3:-2
Thread-3: no ticket

1.5. 创建线程

  • 继承Thread类
  • 实现Runable接口

区别(继承Thread类, 实现Runable接口)

  • 实现的方式避免了单继承的局限性
  • 线程代码存放位置不一样
    • Thread 存放在Thread子类的run方法中
    • Runable 存放在接口子类的run方法中

1.6. 多线程的安全问题

出问题的原因

  • 当多条语句在操作同一个线程的共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,另一个线程就参与进来执行,导致共享数据错误

解决办法:利用”同步代码块”

1
2
3
synchronized(对象){
 需被同步的代码
}
  • 上面的“对象”其实是一个同步锁,持有锁的线程可以在同步中执行,没有持有锁的线程即使获得CPU执行权,也进不去
  • 如何找到“需同步的代码”? –> 看哪些语句在操作共享数据

代码实现:解决售票问题的安全性,避免出现0,-1,-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
package com.leeeyou.ticket;

public class SaleTicketSafe {
public static void main(String[] args) {
TicketSafe t = new TicketSafe();

Thread t1 = new Thread(t);
Thread t2 = new Thread(t);
Thread t3 = new Thread(t);
Thread t4 = new Thread(t);

t1.start();
t2.start();
t3.start();
t4.start();
}
}

class TicketSafe implements Runnable {
public int ticket = 50;//总票数
private boolean flag = true;

@Override
public void run() {
while (flag) {
synchronized (this) { //同步代码块
if (ticket > 0) {
try {
Thread.sleep(100); //制造线程冻结
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "...." + ticket--);
} else {
flag = false;
System.out.println(Thread.currentThread().getName() + ": no ticket");
}
}
}
}

}

结果如下所示:

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
Thread-0....50
Thread-0....49
Thread-3....48
Thread-3....47
Thread-3....46
Thread-3....45
Thread-3....44
Thread-3....43
Thread-3....42
Thread-3....41
Thread-3....40
Thread-3....39
Thread-3....38
Thread-3....37
Thread-3....36
Thread-3....35
Thread-3....34
Thread-3....33
Thread-3....32
Thread-3....31
Thread-3....30
Thread-3....29
Thread-3....28
Thread-3....27
Thread-3....26
Thread-3....25
Thread-3....24
Thread-3....23
Thread-3....22
Thread-3....21
Thread-3....20
Thread-3....19
Thread-3....18
Thread-3....17
Thread-3....16
Thread-3....15
Thread-3....14
Thread-3....13
Thread-3....12
Thread-3....11
Thread-3....10
Thread-3....9
Thread-3....8
Thread-3....7
Thread-3....6
Thread-3....5
Thread-3....4
Thread-3....3
Thread-3....2
Thread-3....1
Thread-3: no ticket
Thread-2: no ticket
Thread-1: no ticket
Thread-0: no ticket

同步的3个前提

  • 两个或两个以上的线程
  • 必须多个线程使用同一个锁
  • 必须保证同步中只能有一个线程在运行

同步的优缺点

  • 优点:解决的多线的安全问题
  • 缺点:多个线程需要判断锁,较为消耗资源

1.7. 同步函数

情景:两个储户分别向银行存钱300元,每次存100,存3次

分析:该线程是否有安全问题,如何找到问题并解决?

  • 明确哪些代码是多线程运行的代码
  • 明确共享数据
  • 明确多线程运行中哪些语句是操作共享数据的

代码实现

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


public class SaveMoney {
  public static void main(String[] args) {
    Cus c = new Cus();
    Thread t1 = new Thread(c);
    Thread t2 = new Thread(c);
    
    t1.start();
    t2.start();
  }
}
class Bank {
  private int count = 0
  public synchronized void add(int n)//同步函数
    count += n ;
    try {
     Thread.sleep(10);
    } catch (InterruptedException e) {
     e.printStackTrace();
    }
    System.out.println("count = " + count);
  }
}
class Cus implements Runnable{
  Bank bank = new Bank();
  @Override
  public void run() {
    for(int i = 0 ; i<3; i++){
     bank.add(100);
    }
  }
}

同步的两种形式

  • 同步代码
  • 同步函数

静态同步函数

  • 同步锁是所属类的字节码文件对象

1.8. 单例设计模式

设计模式之单例模式

1.9. 死锁

出现原因:同步中嵌套同步

写一个死锁程序

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.day11.deadLock;


public class DeadLock {
  public static void main(String[] args) {
    Thread t1 = new Thread(new DeadLock2(false));
    Thread t2 = new Thread(new DeadLock2(true));
    t1.start();
    t2.start();
  }
}


class DeadLock2 implements Runnable{
  boolean flag = true;
  DeadLock2(boolean flag){
    this.flag = flag;
  }
  @Override
  public void run() {
    if(flag){
     synchronized (LockObject.lo1) {
       System.out.println("if lo1");
       synchronized (LockObject.lo2) {
         System.out.println("if lo2");
       }
     }
    }else{
     synchronized (LockObject.lo2) {
       System.out.println("else lo2");
       synchronized (LockObject.lo1) {
         System.out.println("else lo1");
       }
     }
    }
  }
}


class LockObject {
  static LockObject lo1 = new LockObject();
  static LockObject lo2 = new LockObject();
}

2. 多线程进阶

2.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
package com.day12.threadCorrespond;
//未加入同步锁时的代码
public class InputOutputDemo {
public static void main(String[] args) {
Res r = new Res();

new Thread(new Input(r)).start();
new Thread(new Output(r)).start();
}
}

class Input implements Runnable{
private Res r ;
Input(Res r){
this.r = r ;
}
@Override
public void run() {
int i = 0 ;
while(true){
if(i==0){
r.name = "Maroon5";
r.sex = "male";
}else{
r.name = "凯蒂佩里";
r.sex = "女女女";
}
i = (i+1)%2;
}
}
}

class Output implements Runnable{
private Res r ;
Output(Res r){
this.r = r ;
}
@Override
public void run() {
while(true)

System.out.println(r.name + "..." + r.sex);
}
}

class Res {
String name;
String sex;
}
  • 安全问题:加入同步锁
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
package com.day12.threadCorrespond;
//加入同步锁,注意:要使用同一把锁
public class InputOutputDemo {
public static void main(String[] args) {
Res r = new Res();

new Thread(new Input(r)).start();
new Thread(new Output(r)).start();
}
}

class Input implements Runnable{
private Res r ;
Input(Res r){
this.r = r ;
}
@Override
public void run() {
int i = 0 ;
while(true){
synchronized(r){
if(i==0){
r.name = "Maroon5";
r.sex = "male";
}else{
r.name = "凯蒂佩里";
r.sex = "女女女";
}
i = (i+1)%2;
}
}
}
}

class Output implements Runnable{
private Res r ;
Output(Res r){
this.r = r ;
}
@Override
public void run() {
while(true) {
synchronized (r) {
System.out.println(r.name + "..." + r.sex);
}
}
}
}

class Res {
String name;
String sex;
}

  • 交替控制问题:加入等待唤醒机制
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
package com.day12.threadCorrespond;
//加入等待唤醒机制,让姓名、性别逐一赋值再输出
public class InputOutputDemo {
public static void main(String[] args) {
Res r = new Res();

new Thread(new Input(r)).start();
new Thread(new Output(r)).start();
}
}

class Input implements Runnable{
private Res r ;
Input(Res r){
this.r = r ;
}
@Override
public void run() {
int i = 0 ;
while(true){
synchronized(r){
if(r.flag){
try {
r.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}

if(i==0){
r.name = "Maroon5";
r.sex = "male";
}else{
r.name = "凯蒂佩里";
r.sex = "女女女";
}
i = (i+1)%2;
r.flag = true;
r.notify();
}
}
}
}

class Output implements Runnable{
private Res r ;
Output(Res r){
this.r = r ;
}
@Override
public void run() {
while(true) {
synchronized (r) {
if(!r.flag){
try {
r.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(r.name + "..." + r.sex);
r.flag = false;
r.notify();
}
}
}
}

class Res {
String name;
String sex;
boolean flag = false;
}

代码优化

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

//代码优化
public class InputOutputDemo {
public static void main(String[] args) {
Res r = new Res();

new Thread(new Input(r)).start();
new Thread(new Output(r)).start();
}
}

class Input implements Runnable {
private Res r;

Input(Res r) {
this.r = r;
}

@Override
public void run() {
int i = 0;
while (true) {
if (i == 0) {
r.set("Maroon5", "male");
} else {
r.set("凯蒂佩里", "女女女");
}
i = (i + 1) % 2;
}
}
}

class Output implements Runnable {
private Res r;

Output(Res r) {
this.r = r;
}

@Override
public void run() {
while (true) {
r.print();
}
}
}

class Res {
private String name;
private String sex;
boolean flag = false;

public void set(String name, String sex) {
synchronized (this) {
if (flag) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.name = name;
this.sex = sex;
flag = true;
notify();
}
}

public void print() {
synchronized (this) {
if (!flag) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(name + "..." + sex);
flag = false;
notify();
}
}
}

小结

  • wait()
  • notify()
  • notifyAll()

三个方法都使用在同步中

  • 原因:要对持有监视器(锁)的线程操作而监视器(锁)只在同步中出现
  • 注意:等待和唤醒必须是对同一个锁
  • 思考:为什么都定义在Object类中?因为监视器(锁)可以是任意对象

2.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
package com.day12.proCus;
/**
* 这种方式解决"生产者消费者"只适用与两个线程的情况(一个生产一个消费)
* 但是实际往往是多条线程同时工作,但将strat()注释去掉后,四条线程同时工作时就会出问题了:重复消费或者未消费
* @author kongbei
*
*/
public class ProducerCustomerDemo {
public static void main(String[] args) {
Res r = new Res();

Producer p = new Producer(r);
Customer c = new Customer(r);

Thread t1 = new Thread(p);
Thread t2 = new Thread(c);
Thread t3 = new Thread(p);
Thread t4 = new Thread(c);

t1.start();
t2.start();
//t3.start();
//t4.start();
}
}

class Producer implements Runnable {
private Res r;

Producer(Res r) {
this.r = r;
}

@Override
public void run() {
r.set("iPhone5s");
}
}

class Customer implements Runnable {
private Res r;

Customer(Res r) {
this.r = r;
}

@Override
public void run() {
r.print();
}
}

class Res {
private String name;
private int count = 5588;
private boolean flag = false;

public synchronized void set(String name) {
while (true) {
if (flag) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.name = name + "..编号" + count++;
System.out.println(Thread.currentThread().getName() + "- 生产 -" + this.name);
flag = true;
this.notify();
}
}

public synchronized void print() {
while (true) {
if (!flag) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + "-消费-" + name);
flag = false;
this.notify();
}
}
}

生产和消费逐一交替运行(利用JDK1.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
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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package com.leeeyou.produceCustomer;

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

/**
* 解决了"重复消费和未消费"的问题(if改成while),同时利用JDK5.0新特性Lock和Condition 处理了同步时上锁解锁和等待唤醒的的问题
* Lock最大的一个特点是:"可以支持多个相关的 Condition 对象",也就是说一把锁上可以绑定多个"状态条件"对象,详见API
*
* @author kongbei
*/
public class ProducerCustomerDemo2 {
public static void main(String[] args) {
Res2 r = new Res2();

Producer2 p = new Producer2(r);
Customer2 c = new Customer2(r);

Thread t1 = new Thread(p);
Thread t2 = new Thread(c);
Thread t3 = new Thread(p);
Thread t4 = new Thread(c);
Thread t5 = new Thread(p);
Thread t6 = new Thread(c);

t1.setName("T1 - ");
t2.setName("T2 - ");
t3.setName("T3 - ");
t4.setName("T4 - ");
t5.setName("T5 - ");
t6.setName("T6 - ");

t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
t6.start();
}
}

class Producer2 implements Runnable {
private Res2 r;

Producer2(Res2 r) {
this.r = r;
}

@Override
public void run() {
r.set("iPhone5s");
}
}

class Customer2 implements Runnable {
private Res2 r;

Customer2(Res2 r) {
this.r = r;
}

@Override
public void run() {
r.print();
}
}

class Res2 {
private String name;

private volatile List<String> mList = new ArrayList<>();

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

public void print() {
while (true) {
lock.lock(); //上锁
if (mList.size() > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
String remove = mList.remove(0);
System.out.println(Thread.currentThread().getName() + "消费了:" + remove);
pCondition.signal();
} else {
System.out.println("消费光了:" + mList.size());
try {
cCondition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
lock.unlock();//解锁
}
}

public void set(String name) {
while (true) {
lock.lock(); //上锁
if (mList.size() < 50) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
String product = "一个手机 ";
mList.add(product);
System.out.println(Thread.currentThread().getName() + "生产了:" + product);
cCondition.signal();
} else {
System.out.println("生产满了:" + mList.size());
try {
pCondition.await();//让消费线程等待
} catch (InterruptedException e) {
e.printStackTrace();
}
}
lock.unlock();//解锁
}
}
}

2.3. 停止线程(彩蛋链接)

情况分析

  • 只有一种情况,即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
package com.day12.stopThread;
//利用标记结束线程
public class StopThread01 {
public static void main(String[] args) {
Thread01 t1 = new Thread01();
Thread t = new Thread(t1);

t.start();

for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + ".." + i);
if(i==99){
t1.changeFlag();
}
}


}
}

class Thread01 implements Runnable {
private boolean flag = true;

@Override
public void run() {
while (flag) {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName()+".."+i);
}
}
}

public void changeFlag() {
flag = false;
}
}

特殊情况

  • 当线程处于冻结状态,即使设置了标记,线程也不会结束
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.day12.stopThread;
//这种情况下设置了标记,但是线程也不会终止,原因是线程处于冻结状态,无法读取到标记的最新情况
public class StopThread02 {
public static void main(String[] args) {
Thread02 t2 = new Thread02();
Thread t = new Thread(t2);

t.start();

for (int i = 0; i < 100; i++) {
if(i==99){
t2.changeFlag();//修改了标记
}
System.out.println(Thread.currentThread().getName() + ".." + i);
}
}
}

class Thread02 implements Runnable {
private boolean flag = true;

@Override
public synchronized void run() {
while (flag) {
try {
wait(); //线程冻结导致无法读取标记的最新情况
} catch (InterruptedException e) {
System.out.println(Thread.currentThread().getName()+"..Exception");
}
System.out.println(Thread.currentThread().getName()+"..run");
}
}

public void changeFlag() {
flag = false;
}
}
  • 这时需要对冻结状态进行清除,强制让其恢复到运行状态(其实就是获取CPU执行权),此时便可以操作标记来结束线程
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
package com.day12.stopThread;
//利用interrupt方法清楚冻结状态,并终止线程
public class StopThread02 {
public static void main(String[] args) {
Thread02 t2 = new Thread02();
Thread t = new Thread(t2);

t.start();

for (int i = 0; i < 100; i++) {
if(i==99){
t.interrupt();//清除冻结状态,强制让其恢复到运行状态(其实就是获取CPU执行权)
}
System.out.println(Thread.currentThread().getName() + ".." + i);
}
}
}

class Thread02 implements Runnable {
private boolean flag = true;

@Override
public synchronized void run() {
while (flag) {
try {
wait(); //线程冻结导致无法读取标记的最新情况
} catch (InterruptedException e) {
System.out.println(Thread.currentThread().getName()+"..Exception");
flag = false;
}
System.out.println(Thread.currentThread().getName()+"..run");
}
}

public void changeFlag() {
flag = false;
}
}

2.4. 守护线程

使用情况:在启动线程前调用

特点

  • 开启后,和前台线程共同抢夺CPU执行权并运行
  • 结束时,当所有前台线程都结束后,后台线程会自动结束(JAVA VM退出)
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.day12.deamonThread;

public class DeamonThreadDemo {
public static void main(String[] args) {
DeamonThread dt = new DeamonThread();
Thread t1 = new Thread(dt);
Thread t2 = new Thread(dt);

t1.setDaemon(true);//设置为后台线程
t2.setDaemon(true);

t1.start();
t2.start();

for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + ".." + i);
}
}
}

class DeamonThread implements Runnable {

@Override
public void run() {
while (true) {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + ".." + i);
}
}
}

}

2.5. join()

用途:临时加入线程

特点

  • 当A线程执行到了B线程的join()方法,A就会等待B线程都执行完,A才会执行
  • 通俗一点说,这个方法就是用来抢夺CPU执行权
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.day12.deamonThread;

public class DeamonThreadDemo {
public static void main(String[] args) throws InterruptedException {
DeamonThread dt = new DeamonThread();
Thread t1 = new Thread(dt);
Thread t2 = new Thread(dt);

t1.start();

t1.join();

t2.start();

//t1.join();

for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + ".." + i);
}
}
}

class DeamonThread implements Runnable {

@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + ".." + i);
}
}

}

2.6. 优先级以及yield()

yield 暂停当前正在执行的线程对象,并执行其他线程

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.day12;

public class LastProblem {
public static void main(String[] args) throws InterruptedException {
LastThread dt = new LastThread();

Thread t1 = new Thread(dt);
Thread t2 = new Thread(dt);

t1.start();
t2.start();
}
}

class LastThread implements Runnable {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().toString() + ".." + i);
Thread.yield();//交出CPU执行权
}
}
}