一、线程基础内容

1、程序、进程与线程

image.png
image.png
image.png

1、程序:Program,是一个指令的集合
2、进程:Process,(正在执行中的程序)是一个静态的概念

进程是程序的一次静态执行过程,占用特定地的地址空间
每个进程都是独立的,由3部分组成cpu,data,code
缺点:内存的浪费,cpu的负担

3、线程:是进程中一个“单一的连续控制流程”/执行路径

线程又被成为轻量级进程
Threads run at the same time,independently of one another
一个进程可拥有多个并行的线程
一个进程中的线程共享相同的内存单元/内存地址空间->可以访问相同的变量和对象,而且他们从同一堆中分配对象->通信、数据交换、同步操作
由于线程间的通信是在同一地址空间上进行的,所以不需要额外的通信机制,这就使得通信更简便而且信息的传递速度也更快

2、线程的创建和启动

2.1、第一种方式

image.png
继承Thread类,重新run方法,调start(启动线程),每次运行相同的代码,出来的结果可能不一样,原因在于多线程谁先抢占资源无法进行认为控制

package com.msbline.threadPkg;
public class ThreadDemo extends Thread{
    @Override
 public void run() {
        for (int i = 0; i < 10; i++){
            System.out.println(Thread.currentThread().getName() +"---"+ i);
        }
    }
    public static void main(String[] args) {
        ThreadDemo threadDemo = new ThreadDemo();
        threadDemo.start();
        for (int i = 0; i < 10; i++){
            System.out.println(Thread.currentThread().getName() +"==="+ i);
        }
    }
}
2.2、第二种方式

image.png
实现Runnable接口,重写run方法,创建Thread对象,将刚刚创建好的Runnable的子类实现作为Thread的构造参数,通过Trhead.start()进行启动

package com.msbline.threadPkg;
public class ThreadDemo02 implements Runnable{
    @Override
 public void run() {
        for (int i = 0; i < 10; i++){
            System.out.println(Thread.currentThread().getName() +"---"+ i);
        }
    }
    public static void main(String[] args) {
        ThreadDemo threadDemo = new ThreadDemo();
        new Thread(threadDemo).start();
        for (int i = 0; i < 10; i++){
            System.out.println(Thread.currentThread().getName() +"==="+ i);
        }
    }
}
两种方式哪种使用更多

image.png
image.png

3、线程的生命周期

image.png
image.png
image.png

4、线程的代理设计模式

image.png

5、线程操作的相关方法

image.png

1、sleep 方法是属于 Thread 类中的,sleep 过程中线程不会释放锁,只会阻塞线程,让出cpu给其他线程,但是他的监控状态依然保持着,当指定的时间到了又会自动恢复运行状态,可中断,sleep 给其他线程运行机会时不考虑线程的优先级,因此会给低优先级的线程以运行的机会

2、yield和 sleep 一样都是 Thread 类的方法,都是暂停当前正在执行的线程对象,不会释放资源锁,和 sleep 不同的是 yield方法并不会让线程进入阻塞状态,而是让线程重回就绪状态,它只需要等待重新获取CPU执行时间,所以执行yield()的线程有可能在进入到可执行状态后马上又被执行。还有一点和 sleep 不同的是 yield 方法只能使同优先级或更高优先级的线程有执行的机会

3、join,等待调用join方法的线程结束之后,程序再继续执行,一般用于等待异步线程执行完结果之后才能继续运行的场景。例如:主线程创建并启动了子线程,如果子线程中药进行大量耗时运算计算某个数据值,而主线程要取得这个数据值才能运行,这时就要用到 join 方法了

4、wait 方法是属于 Object 类中的,wait 过程中线程会释放对象锁,只有当其他线程调用 notify 才能唤醒此线程。wait 使用时必须先获取对象锁,即必须在 synchronized 修饰的代码块中使用,那么相应的 notify 方法同样必须在 synchronized 修饰的代码块中使用,如果没有在synchronized 修饰的代码块中使用时运行时会抛出IllegalMonitorStateException的异常

二、线程同步

1、线程同步的必要性

image.png
image.png

多个线程访问同一个共享数据的时候,会出现数据安全问题,比如买票,两个线程同时对一张票进行操作,可能会导致重票的问题

2、线程同步的实现

2.1、同步代码块

synchronized(共享资源,共享对象,需要是Object的子类){具体执行的代码块}

public class TicketRunnable2 implements Runnable{
    private int ticket = 5;
    @Override
 public void run() {
        for(int i = 0; i<100; i++){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (this){
                if(ticket > 0){
                    System.out.println(Thread.currentThread().getName()+"正在出售第"+(ticket--)+"票");
                }
            }
        }
    }
    public static void main(String[] args) {
        TicketRunnable2 ticketRunnable = new TicketRunnable2();
        Thread t1 = new Thread(ticketRunnable,"A");
        Thread t2 = new Thread(ticketRunnable,"B");
        Thread t3 = new Thread(ticketRunnable,"C");
        Thread t4 = new Thread(ticketRunnable,"D");
        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }
}
2.2、同步方法
public class TicketRunnable3 implements Runnable{
    private int ticket = 5;
    @Override
 public void run() {
        for(int i = 0; i<100; i++){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            this.sale();
        }
    }
    /**
 * 使用同步方法解决
 */
 public synchronized void sale(){
        if(ticket > 0){
            System.out.println(Thread.currentThread().getName()+"正在出售第"+(ticket--)+"票");
        }
    }
    public static void main(String[] args) {
        TicketRunnable3 ticketRunnable = new TicketRunnable3();
        Thread t1 = new Thread(ticketRunnable,"A");
        Thread t2 = new Thread(ticketRunnable,"B");
        Thread t3 = new Thread(ticketRunnable,"C");
        Thread t4 = new Thread(ticketRunnable,"D");
        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }
}

3、死锁

image.png

4、线程同步小结

image.png

三、线程间通信

1、线程间通信的必要性

image.png
一般来说,每个线程自己完成自己的任务就可以了,但有时候,线程的处理会依赖另一个线程的数据,所以就需要线程间通信,来达到同步信息的效果。

2、线程间通信的实现

参考:https://blog.csdn.net/jisuanji12306/article/details/86363390


萌妹子_liu
28 声望43 粉丝

萌萌哒,程序猿