目录
  1. 1. 一 、线程的创建
    1. 1.0.1. 1、继承Thread类或者其子类
    2. 1.0.2. 2、自己创建一个实现类实现Runnable
    3. 1.0.3. 3、 还有一种暂时可能用不到 Callable接口
    4. 1.0.4. 4 补充 函数式接口
  2. 1.1. 二、线程的运行
    1. 1.1.1. 1 停止
    2. 1.1.2. 2 休眠
    3. 1.1.3. 3 礼让
    4. 1.1.4. 4 强制执行
    5. 1.1.5. 5 线程状态
    6. 1.1.6. 6 线程优先级
    7. 1.1.7. 7 守护线程
  3. 1.2. 三、线程的同步
    1. 1.2.1. 1 锁
    2. 1.2.2. 2 死锁
    3. 1.2.3. 3 lock锁
  4. 1.3. 四、线程协作
多线程

一个进程包含多个线程,通过时间片的轮转

一 、线程的创建

Runnable是Java中用以实现线程的接口,包含了run方法,可以通过以下两个方法实现这个接口

1、继承Thread类或者其子类
  • 方法 run 线程相关的代码写在这里,一般要重写 (run是Runnable唯一的方法)

    ​ join 优先执行

    ​ start 使用start开启多线程

    ==注意==

    • main函数和实现类程序执行顺序按CPU安排来定,你事先并不知道先后顺序
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    //创建线程方法1,继承Thread类,重写run方法,使用start开启线程
    public class Thread1 extends Thread {
    @Override
    public void run(){
    for (int i = 0; i < 20; i++) {
    System.out.println("我" + i);
    }
    }

    public static void main(String[] args) {
    Thread1 t = new Thread1();
    t.start();
    for (int i = 0; i < 1000; i++) {
    System.out.println("爱你" + i);
    }
    }
    }
    • 多个实现类对象同时执行,顺序也是无法去确定的
2、自己创建一个实现类实现Runnable
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//创建线程第二个方法
public class Runnable1 implements Runnable {
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println("我" + i);
}
}

public static void main(String[] args) {
Runnable1 r = new Runnable1();
new Thread(r).start();
for (int i = 0; i < 1000; i++) {
System.out.println("爱你" + i);
}
}
}
3、 还有一种暂时可能用不到 Callable接口
4 补充 函数式接口
  • 只有唯一一个抽象方法的接口
  • 可以通过LAMBDA表达式来创建该接口的对象
  • 函数式接口的实现有很多方法
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
public class TestLambda1 {
//3.静态内部类
static class Like2 implements ILike{
@Override
public void lambda () {
System. out.println("i like lambda2") ;
}

public static void main (String[] args) {
ILike1 like = new Like () ;
like. lambda() ;
like = new Like2 () ;
like. lambda () ;

//4.局部内部类
class Like3 implements ILike {
@Override
public void lambda () {
System. out.println("i like lambda3") ;
}
}
like = new Like3() ;
like. lambda () ; .
//5.匿名内部类,没有类的名称,必须借助接口或者父类
like = new ILike () {
@Override
public void lambda () {
System. out.println("i like lambda4") ;
};
like. lambda () ;
}
/*6.用lambda进一步简化匿名内部类
避免匿名内部类过多
括号里参数类型可省略,只有一行代码时大括号也可省略,只有一个参数时小括号可省略*/
like = ()->{
System. out.println("i like lambda5") ;
};
1ike. lambda () ;
}
//1.定义一个函数式接口
interface ILike{
void lambda () ;
}
//2.实现类
class Like
implements ILike1 {
@Override
public void lambda () {
System.out.println("i like lambda") ;
}
}

二、线程的运行

image-20200307102633910

1 停止
  • 不推荐使用JDK提供的stop() destroy()方法,已废弃
  • 推荐线程自己停止下来 ,建议使用一个标志位进行终止变量,当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
/*测试停止线程
1、建议使用次数正常停止
2、建议使用标志位
3、不要使用stop或者destory等过时的方法,JDK都画掉了
*/
public class TestStop implements Runnable{
//1、设置一个标识
private boolean flag = true;
@Override
public void run() {
int i = 0;
while (flag)
System.out.println("Thread is running" + i++);
}
//2、设置一个公开的方法停止线程
public void stop(){
this.flag = false;
}
public static void main(String[] args) {
TestStop t = new TestStop();
new Thread(t).start();
for (int i = 0; i <1000 ; i++) {
System.out.println("main is running" + i);
if(i == 900)
t.stop();
System.out.println("线程停止了");
}
}
}
2 休眠
  • sleep (时间)指定当前线程阻塞的毫秒数;
  • sleep存在异常 InterruptedException,
  • sleep时间达到后线程进入就绪状态;
  • sleep可以模拟网络延时(放大问题发生性),倒计时等。
  • 每一个对象都有一个锁,sleep不会释放锁;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//模拟倒计时
public class TestSleep2 {
public static void main(String[] args) {
try {
tenDown() ;
} catch (InterruptedException e) {
e. printStackTrace() ;
}
}
public static void tenDown() throws Inter ruptedException {
int num=10;
while (true){
Thread.sleep( millis: 1000) ;
System.out.println(num--);
if (num<=0)
break;
}
}
}
3 礼让
  • 礼让线程,让当前正在执行的线程暂停,但不阻塞
  • 将线程从运行状态转为就绪状态 让cpu重新调度
  • ==礼让不一定成功!==看CPU心情
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
)//测试礼让线程
)// 礼让不一定成功,看CPU心情
public class TestYield {
public static void main(String[] args) {
MyYield myYield = new MyYield();
new Thread (myYield, name: "a") .start();
new Thread (myYield, name: "b") .start() ;
}
}
class MyYield implements Runnable{
@Override
public void run() {
System.out.println(Thread . currentThread().getName() +"线程开始执行");
Thread.yield();//礼让
System. out .println(Thread . currentThread() . getName()+"线程停止执行");
}
}
4 强制执行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class TestJoin implements Runnable {
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println("线程vip来了" + i);
}
}

public static void main(String[] args) throws InterruptedException {
//启动我们的线程
TestJoin testJoin = new TestJoin();
Thread thread = new Thread(testJoin);
thread.start();
//主线程
for (int i = 0; i < 500; i++) {
if (i == 200) {
thread.join();//插队
System.out.println("'main" + i);
}
}
}
}
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
public class TestState {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("///////");
});
//观察状态
Thread.State state = thread.getState();
System.out.println(state); //NEW
//观察启动后
thread.start(); //启动线程
state = thread.getState();
System.out.println(state); //Run
while (state != Thread.State.TERMINATED) {//只要线程不终止,就一直输出状态
Thread.sleep(100);
state = thread.getState(); //. 更新线程状态
System.out.println(state); //输出状态
}

}
}
6 线程优先级
  • Java提供一个线程调度器来监控程 序中启动后进入就绪状态的所有线程,线程调度
    器按照优先级决定应该调度哪个线程来执行。线程的优先级用数字表示,范围从1~10.
  • Thread.MIN PRIORITY = 1;
    Thread.MAX_ PRIORITY = 10;
    Thread.NORM PRIORITY = 5;
  • 使用以下方式改变或获取优先级. getPriority() . setPriority(int xx)
  • 但是优先级只是影响调度概率,不是一定
7 守护线程

设置为守护线程后,该线程会随着用户线程结束

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
public class TestDaemon {
public static void main(String[] args) {
God god = new God() ;
You you = new You() ;
Thread thread = new Thread(god) ;
thread . setDaemon(true); //默认是false表示是用户线程,正常的线程都是用户线程
thread.start(); //上帝守护线程启动
new Thread(you) .start(); //你 用户线程启动...
}
//上帝
class God implements Runnable{
@override
public void run() {
while (true) {
System. out . println("上帝保佑着你");
}
}
}
//你
class You implements Runnable{
@Override
public void run() {
for(inti=0;i<36500;i++){
System. out . println("你一生都开心的活着") ;
}
System. out .println("-====goodbye! world!======");
}

三、线程的同步

1 锁
  • synchronized方法控制对“对象”的访问,每个对象对应一 -把锁 ,每个synchronized方法都必须获得调用该方法的对象的锁才能执行,否则线程会阻塞,方法一旦执行,就独占该锁,直到该方法返回才释放锁,后面被阻塞的线程才能获得这个锁,继续执行
  • 不能直接锁run,如果run调用了其他方法,可以锁那个调用的方法,如果是直接在run里面写的方法,要用synchronczed块锁

synchronized (){}

2 死锁

产生死锁的四个必要条件:

  1. 互斥条件:一个资源每次只能被一一个进程使用。
  2. 请求与保持条件: 一个进程因请求资源而阻塞时,对已获得的资源保持不放。
  3. 不剥夺条件 :进程已获得的资源,在末使用完之前,不能强行剥夺。
  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
//死锁:多个线程互相抱着对方需要的资源, 然后形成僵持.
public class DeadLock {
public static void main(String[] args) {
Makeup g1 = new Makeup(0, "灰姑凉");
Makeup g2 = new Makeup(1, "白雪公主");
g1.start();
g2.start();

}
}
//口红
class Lipstick {
}

//镜子
class Mirror {
}

class Makeup extends Thread {
//需要的资源只有一份,用static来保证只有一份
static Lipstick Lipstick = new Lipstick();
static Mirror mirror = new Mirror();
int choice; //选择
String girlNmae; //使用化妆品的人

Makeup(int choice, String girlNmae) {
this.choice = choice;
this.girlNmae = girlNmae;
}

@Override
//化妆
public void run() {
try {
makeup();
} catch (InterruptedException e) {
e.printStackTrace();
}
}

//化妆,互相持有对方的锁,就是需要拿到对方的资源
private void makeup() throws InterruptedException {
if (choice == 0) {
synchronized (Lipstick) {//获得口红的锁
System.out.println(this.girlNmae + "获得口红的锁");
Thread.sleep(1000);
}
synchronized (mirror) { //- 秒钟后想获得镜子
System.out.println(this.girlNmae + "获得镜子的锁");
}
}
else{
synchronized (mirror) {//获得镜子的锁
System.out.println(this.girlNmae + "获得镜子的锁");
Thread.sleep(2000);
}

synchronized (Lipstick) { //- 秒钟后想获得口红
System.out.println(this.girlNmae + "获得口红的锁");
}
}
}
}
3 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
//测试Lock锁
public class TestLock {
public static void main(String[] args) {
TestLock2 testLock2 = new TestLock2() ;
new Thread(testLock2) .start();
new Thread (testLock2) .start() ;
new Thread(testLock2) .start() ;
}
}
class TestLock2 implements Runnable{
int ticketNums = 10;
//定义lock锁
private final ReentrantLock lock = new ReentrantLock(){
@override
public void run() {
while (true) {
try {
lock. lock(); //加锁
if (ticketNums>0) {
try {
Thread . sleep( millis: 1000) ;
} catch (Inter ruptedException e) {
e. printStackTrace() ;
System .out . pr intln(ticketNums--) ;
}else
break;
}finally {
//解锁
Lock . unlock() ;
}
}
}

四、线程协作

文章作者: liuDH
文章链接: http://yoursite.com/2020/03/01/%E5%A4%9A%E7%BA%BF%E7%A8%8B/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 毛毛裤裤的世界
打赏
  • 微信
  • 支付寶