Java学习笔记(十七)--进程与线程

概念

进程概念

  • 是程序的一次执行过程,或者是运行的一个程序;是动态的过程:有自身的产生、存在和消亡的过程

线程概念

  • 线程由进程创建,是进程的一个实体
  • 一个进程可以拥有多个线程

其他相关概念

  • 单线程:同一时刻,只允许执行一个线程
  • 多线程:同一时刻可以执行多个线程
  • 并发:同一时刻,多个任务交替执行,如单核CPU实现多任务
  • 并行:同一时刻,多任务同时执行,如多核CPU可实现并行

线程基本使用方式

Thread类

使用方式

  • 继承Thread类,重写run方法
1
2
3
4
5
6
7
class Test extends Thread {

@Override
public void run() {
//填写自己的逻辑代码
}
}

运行原理

运行原理

runnable接口

使用方式

  • 实现runnable接口,重写run方法

    1
    2
    3
    4
    5
    6
    class Test implements Runnable {
    @Override
    public void run() {
    //逻辑代码
    }
    }

多线程执行

  • 示例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    class Test implements Runnable {
    @Override
    public void run() {
    //逻辑代码
    }
    }

    //main
    Test t1 = new Test();
    Test t2 = new Test();
    Thread thread1 = new Thread(t1);
    Thread thread2 = new Thread(t2);
    thread1.start();
    thread2.start();
    System.out.println("main线程继续执行...")

运行原理

多线程运行原理

区别

  • Java是单继承机制,在某些情况下一个类已经继承了某个父类,这种情况下无法使用继承Thread类方法来创建线程

  • 实现 Runnable接口方式更加适合多个线程共享一个资源的情况,避免了单继承机制

线程终止

  • 当线程完成任务后,会自动退出

  • 通知模式:通过变量控制run方法退出的方式停止线程

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    class Test implements Runnable {
    boolean fool = true;//控制循环
    int count = 0;//循环计次
    @Override
    public void run() {
    while (fool) {
    count++;
    }
    if (count == 10) {
    fool = false;
    }
    }
    }

线程常用方法

常用方法

1
2
3
4
5
6
7
8
9
10
1. setName //设置线程名称,使之与参数name相同
2. getName //返回
3. start //运行该线程;Java虚拟机底层调用该线程的start0方法
4. run //调用线程对象的run方法
5. setPriority //更改线程的优先级
6. getPriority //获取线程的优先级
7. sleep //在指定的毫秒数内让当前正在执行的线程休眠(暂停执行)
8. interrupt //中断线程
9. yield //线程礼让,让出cpu,让其他线程执行,礼让时间不确定,所以礼让不一定成功
10. join //线程插队,插队的线程一旦插队成功,则先执行完插入的线程的所有任务
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
public class ThreadMethod01 {
public static void main(String[] args) throws InterruptedException {
T t = new T();
t.setName("执笔");//设置线程名字
t.setPriority(Thread.MIN_PRIORITY);//设置优先级为最小
t.start();//运行线程

System.out.println(t.getName());//获取线程名字
for (int i = 0; i < 5; i++) {
//休眠1s
Thread.sleep(1000);
System.out.println(t.getName() + "等待中..." + i);
}
t.interrupt();//中断线程
System.out.println(t.getName() + " 线程的优先级 " + t.getPriority());

}
}

class T extends Thread {

@Override
public void run() {
while(true) {
for (int i = 0; i <= 100; i++) {
System.out.println(Thread.currentThread().getName() + " 吃包子..." + i);
}
//线程休眠20s
try {
Thread.sleep(20000);
} catch (InterruptedException e) {
System.out.println(Thread.currentThread().getName() + "休眠中...");
}
}
}
}

注意事项和细节

  • start底层会创建新的线程,调用run(),run就是一个简单的方法调用,不会启动新线程
  • 线程的优先级范围(1-10级)
  • interrupt 中断线程,但并没有真正结束线程,一般用于中断正在休眠的线程
  • sleep 线程的静态方法,使当前线程休眠

用户线程

  • 也叫工作线程,当线程的任务执行玩或者通知方式结束

守护线程

  • 一般为工作线程服务,当所有的用户线程结束,守护线程自动结束
  • 常见的守护线程:垃圾回收机制
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
public class ThreadMethod01 {
public static void main(String[] args) throws InterruptedException {
MyDaemonThread dt = new MyDaemonThread();
//将dt 设置为守护线程,当所有线程结束后,dt也就自动结束
//如果没有设置,那么即使main线程执行完毕,dt也不退出
dt.setDaemon(true);
dt.start();
for (inti= 1; i<= 100; i++) {
Thread.sleep(50);
System.out.println(“执笔学习中-----" + i);
}
}
}

class MyDaemonThread extends Thread {
public void run() {
for (;;){
try {
Thread.sleep(50);
} catch (InterruptedException e) {
//TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("学习中~~~");
}}}

线程生命周期

线程状态转换

线程同步

  • 当有一个线程在对内存进行操作时,其他线程都不可以对这个内存地址进行操作,直到该线程完成操作

Synchronized

同步代码块
1
2
3
synchronized (对象) {//得到对象的锁,才能操作同步代码
//需要被同步的代码;
}
同步方法
1
2
3
public synchronized void m(String name) {
//需要被同步的代码
}

互斥锁

基本介绍

  • 对象互斥锁来保证共享数据操作的完整性
  • 每个对象都对应于一个可称为“互斥锁”的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象
  • 关键字synchronized来与对象的互斥锁联系。当某个对象用synchronized修饰时,表明该对象在任一时刻只能由一个线程访问
  • 同步的局限性:导致程序的执行效率低
  • 同步方法(非静态的)的锁可以是this,也可以是其他对象(要求是同一个对象)
  • 同步方法(静态的)的锁为当前类本身

注意事项

  • 同步方法如果没有使用static修饰(非静态方法):默认锁对象为this
  • 如果方法使用static修饰(静态方法),默认锁对象:当前类.class

线程死锁

  • 多个线程都占用了对方的锁资源,会导致死锁,需要尽量避免死锁发生

释放锁

释放锁情形

  • 当前线程的同步方法、同步代码执行结束
  • 当前线程在同步代码块、同步方法中遇到break、return
  • 当前线程在同步代码块、同步方法中出现了未处理的Error或Exception,导致程序异常结束
  • 当前线程在同步代码块、同步方法中执行了线程对象的wait()方法,当前线程暂停,并释放锁

不会释放锁情形

  • 线程执行同步代码块、同步方法时,程序调用Thread.sleep()、Thread.yield()方法暂停当前线程的执行,不会释放锁
  • 线程执行同步代码块时,其他线程调用了该线程的suspend()方法将该线程挂起,不会释放锁