多线程学习 java

概述

  • 进程:
    1:引入原因:为描述并发下程序的执行情况。
    2:定义:进程是正在运行的程序。是系统进行资源分配的调用的独立单位,每一个进程都有它自己的内存空间和系统资源。
    3:特征:并发性 / 独立性 / 异步性 / 动态性 / 结构特性:进程=程序段+数据段+PCB
  • 线程:
    是进程中的单个顺序控制流,是一条执行路径。
  • 进程和程序的区别与联系
    ①进程是一个动态的概念;程序是一个静态的概念;
    ②进程具有并发性,而程序没有;
    ③进程是资源分配和处理机调度的独立单位,其并发性受系统制约;
    ④一个程序,多次执行,对应多个进程;不同的进程可以包含同一程序。

实现多线程

继承Thead方法实现多线程

public class Thread
extends Object
implements Runnable

  • 线程是程序中执行的线程。 Java虚拟机允许应用程序同时执行多个执行线程。

创建一个新的执行线程有两种方法:

  • 一:是将一个类声明为Thread的子类。 这个子类应该重写Thread类的方法run。 然后可以分配并启动子类的实例。
    1:创建Mythead继承Thread类
    2:重写方法run
    3:创建Mythread对象
    4:启动线程

  • 需要用到的两个Teread类的方法
    1:public void run() 用来封装被线程重写的方法。 Thread的Thread应该覆盖此方法。
    2:public void start()导致此线程开始执行; Java虚拟机调用此线程的run方法。结果是两个线程同时运行:当前线程(从调用返回到start方法)和另一个线程(执行其run方法)。 不止一次启动线程是不合法的。 特别地,一旦线程完成执行就可能不会重新启动。
    异常 :IllegalThreadStateException - 如果线程已经启动。

  • 代码演示:

public class Mythread extends Thread {
    @Override
    public void run() {
        for (int i = 0; i <50; i++) {
            System.out.println(i);
        }
    }
}
public class MytheadDemo {
    public static void main(String[] args) {
        Mythread thread1=new Mythread();
        Mythread thread2=new Mythread();
        thread1.start();
        thread2.start();
    }
}
  • currentThread()
    public static Thread currentThread()返回对当前正在执行的线程对象的引用。
public class MytheadDemo {
    public static void main(String[] args) {
        System.out.println(Thread.currentThread().getName());
    }
}

在这里插入图片描述

线程的调度(优先级设置)

线程调度的两种模型:
1:分时调度模型:就绪队列的线程轮流使用CPU,平均分配时间片
2:抢占式调度模型:优先级高的优先占用CPU,优先级相同的抢占式占用CPU。优先级高的获得的时间片相对多。

  • java中使用setPriority/getPriority来设置/得到线程的优先级

  • public final void setPriority(int newPriority)
    更改此线程的优先级。
    首先调用这个线程的checkAccess方法,没有参数。 这可能会导致投掷SecurityException 。
    异常 :
    IllegalArgumentException - 如果优先级不在 MIN_PRIORITY(1)到 MAX_PRIORITY (10)
    SecurityException - 如果当前线程不能修改此线程。

  • public final int getPriority()
    返回此线程的优先级。

在这里插入图片描述
上图可以看到线程最大优先级是10,最小1,默认5

public static void main(String[] args) {
        Mythread mythread1=new Mythread();
        Mythread mythread2=new Mythread();
        System.out.println(mythread1.getPriority());
        mythread1.setPriority(Thread.MIN_PRIORITY)}

线程控制三种方法

  • join
    public final void join(long millis) throws InterruptedException
    等待这个线程死亡的时间为millis毫秒。 0的超时意味着永远等待。

  • public static void sleep(long millis)throws InterruptedException
    使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行),具体取决于系统定时器和调度程序的精度和准确性。 线程不会丢失任何显示器的所有权。

  • public final void setDaemon(boolean on)
    将此线程标记为守护线程或用户线程。 当运行的唯一线程都是守护进程线程时,Java虚拟机将退出。 线程启动前必须调用此方法。
    守护线程守护的是主线程,所以当主线程结束,守护线程也会迅速完毕(不是立即)。

public static void main(String[] args) {
        Mythread mythread1=new Mythread();
        Mythread mythread2=new Mythread();
        Thread.currentThread().setName("主线程");//当前线程为主线程,这里是设置一个名字
        //设置mythread1/2为守护线程
        mythread1.setDaemon(true);
        mythread2.setDaemon(true);
        mythread1.start();
        mythread2.start();
        mythread1.run();
        mythread2.run();
        for (int i = 0; i <10 ; i++) {
            System.out.println(Thread.currentThread().getName()+i);
        }//这个结束后主线程就结束了,守护线程也迅速结束
        
    }

线程的生命周期

在这里插入图片描述

实现 Runnable接口方式实现多线程

自定义类实现Runnable接口,将自定义类的对象传入Thread构造函数的参数。

  • Thread构造函数
    Thread(Runnable target, String name)
    分配一个新的 Thread对象

好处是不影响自定义类的继承,自定义类可以作为同一个资源供多个线程使用。

代码示范:

public class Mythread implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i <50; i++) {
            System.out.println(i);
        }
    }
}
public class MytheadDemo {
    public static void main(String[] args) {
        Mythread mythread1=new Mythread();
        Thread thread1=new Thread(mythread1,"线程1");
        thread1.run();

    }
}

线程同步

  • 案例练习:卖票
    在这里插入图片描述
public class SellTickes implements Runnable {
    private    int tickes;

    public SellTickes() {
        this.tickes=100;
    }

    public int getTickes() {
        return tickes;
    }

    @Override
    public void run() {
        if (this.tickes>0){
            this.tickes--;
        }
    }
}
public class SellTickesDemo {
    public static void main(String[] args) {
        SellTickes alltic=new SellTickes();
        Thread tic1=new Thread(alltic,"售票口1");
        Thread tic2=new Thread(alltic,"售票口1");
        Thread tic3=new Thread(alltic,"售票口1");
        tic1.start();
        tic2.start();
        tic3.start();
        int ticket;
        while (true){
            tic1.run();
            tic2.run();
            tic3.run();
            ticket=alltic.getTickes();
            System.out.println(ticket);
        }
    }
}

上面代码,如果在加上Sleep每个进程休眠一段时间,会导致一张票被埋多次,票出现负数。
在这里插入图片描述
在这里插入图片描述

  • 同步代码块解决多个线程同时访问一段代码
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

生产者消费者

发布了43 篇原创文章 · 获赞 12 · 访问量 1408

猜你喜欢

转载自blog.csdn.net/qq_42411214/article/details/104403575