多线程:

   线程是一个进程的执行场景/执行单元;

   进程是一个应用程序/软件,一个进程可以启动多个线程;

   每个进程之间,内存资源不共享;

   线程与线程之间,堆内存与方法区内存共享,但栈内存独立,一个线程一个栈;

   Java中,多线程的机制存在就是为了提高程序的效率;

线程的实现方法:

   在java中,实现线程有三个方法;

第一种方法:

   编写一个类,直接继承java.long.Thread,重写一个类,(必须)重写run方法;

   如何创建线程,使用new对象的方式即可;

   如何启动线程,调用strat()方法即可;

   Strat() 启动一个分支线程,在jvm中开辟一个新的栈内存空间;

   Strat() 方法的作用只是为了启动线程,任务完成会马上结束;

   线程启动成功之后,会自动调用run()方法;

 :其中分支线程中的run()方法不需要手动调用,而是由jvm线程调度机制来运作;

第二种方法:

   编写一个类,然后实现java.lang.runnable接口,实现run方法;

  第二个方法和第一个方法其实大同小异,只是把继承java.lang.Thread,改变成实现Java.lang.runnable接口,开启分支栈方法依然是start();

  在实际开发中,建议使用第二种方法,拓展性较好,面向接口;

线程的生命周期:

  每个线程都会都五个状态,分别是:

  ·新建状态:当new出来的线程调用start()方法之后,线程会进入就绪状态;

  ·就绪状态:又称可运行状态,当前状态的线程具有抢夺CPU时间片的权利,(CPU时间片就是执行权)当线程抢到执行权之后,会执行run()方法,run()方法执行就表示进入了运行状态;

  ·运行状态:当CPU时间片(执行权)用完之后,线程会重新回到就绪状态,继续抢夺执行权,当再次抢夺执行权成功之后,线程又会重新进入运行状态,以此类推;

  ·阻塞状态:当线程遇到阻塞状态,例如:接收用户键盘输入,或者sleep方法等,此时线程会进入阻塞状态,阻塞状态的线程会放弃之前抢夺到的CPU时间片(执行权),当阻塞状态解除之后,会进入就绪状态,抢夺CPU时间片;

  ·死亡状态:当run()方法执行结束之后,线程进行死亡状态;

:线程会在就绪和运行状态频繁切换;

线程的生命周期运作图:

 

获取线程的名字:

   ·getName();获取线程名字;

   ·setName();设置/修改线程名字;

   在没设置线程名字之前,线程默认名字为Thread-0(0表示第一个线程)、Thread-1(1表示第二个线程),以此类推,以一递进;

   ·currentThread();获取当前线程,它是一个静态方法;使用Thread.currentThread(),该方法出现在哪个线程内获取的就是哪个线程;

   ·sleep();让当前线程进入休眠状态,进入阻塞状态,放弃CPU时间片(执行权)让其他线程使用,它是一个静态方法,括号内传的参数是一个毫秒值;

    调用语法:Thread.sleep(1000); 让当前线程休眠一秒钟;

    该sleep()方法出现在哪个线程中,就是指哪个线程休眠;

    Sleep()方法可以完成在指定时间,去完成指定代码的效果,这种效果类似于定时器;

   ·interrupt();终止线程的休眠,唤醒正在睡眠的线程;(这种终断方式依靠了java的异常机制)

   ·stop()终止线程执行,该方法已过时,这种方法是直接把一个线程杀死,因此存在缺点,容易丢失数据;

如何合理的终止一个线程?

   使用一个布尔标识,然后配合if…else语句,使用return;终止即可,如果需要保存数据,即在return;之前编写保存数据代码即可;

线程调度:

  实例方法:

   Void setPriority(int newPriority);设置线程的优先级;

   Int getPriority();获取线程的优先级;

    线程最低优先级为:1;

    线程默认优先级为:5;

    线程最低优先级为:10;

(优先级高的获取CPU时间片会更多一些,但也不完全是,只是概率上提高了)

静态方法:

  Static void yield();让位方法,暂停当前正在执行的线程,让其他线程执行,该方法会让“运行状态”的线程回到“就绪状态”,该方法不是阻塞方法;

  实例方法:

  void join();合并线程

线程在三个条件下,会存在线程安全问题;

  ·多线程并发;

  ·有共享数据;

  ·共享数据有修改行为;

解决线程的安全问题;

  ·不能线程并发,须线程排队执行;该方式又称线程同步机制;

同步和异步:

  ·同步编程模型,就是线程同步机制;(效率低)

  ·异步编程模型,就是多线程并发;(效率高)

线程同步机制的语法:

  ·synchronized(){

    //线程同步代码块;

    }

  ·synchronized小括号中,传递的参数相当关键,而这个参数必须是多线程共享的数据,才能达到线程同步;

  ·synchronized亦可在实例方法上使用;

:synchronized在开发中,最好不要嵌套使用,因为嵌套使用synchronized程序很容易会出现“死锁”;

  死锁是很诡异的存在,发生死锁,程序不会出现任何错误,但程序就是无法往下执行;

Java中三大变量:

   实例变量:在堆中;(存在线程安全问题)

   静态变量:在方法区中;(存在线程安全问题)

   局部变量:在栈中;(不存在线程安全问题)

对象锁和类锁:

  ·对象锁是一个对象一把锁,100个对象,就有100把锁;

  ·类锁,永远只有一把锁,不管创建了多少个对象;

任何解决线程安全问题?

  ·尽量使用局部变量来代替“实例变量”和“静态变量”;

  ·如果一定要使用实例变量,那么可以考虑创建多个对象,这样实例变量的内存就不共享了,数据不共享就没有线程安全问题;

  ·如果不能使用局部变量,创建多个对象也不行,那么再选择使用synchronized关键字;

守护线程:

  Java语言中,线程分两大类:

   一种是用户线程,又称普通线程;(主线程main()就是一个用户线程)

   一种是守护线程,又称后台线程,(其他gc()垃圾回收机制就是守护线程)

守护线程有一个特定:

  守护线程一般都是死循环;

  用户线程结束,守护线程就会自动结束;

  开启守护线程的语法:

  引用.setDaemon(true);在启动线程之前,将线程开启为守护线程即可;

  只有用户线程结束。那么守护线程也会跟着结束;

实现线程的第三种方法:实现Callable接口,(jdk8的新特性)

  这种实现线程的方式可以获取线程返回值;

  前面的两种无法获取线程返回值,因为run()方法返回的是void;

  这种方法第一步需要创建一个“未来任务类”对象,参数需要传入一个Callable接口的实现类对象;

使用Callable接口实现的线程优点与缺点;

 优点:可以获取线程执行完毕后的返回值;

 缺点:效率低,会导致当前线程的阻塞状态,

Object中的wait和notify方法:

 ·wait和notify方法不是线程对象的方法,而是java中任何一个对象都有的方法,是Object类中自带的;

 ·wait和notify不是通过线程对象去调用的;

Wait方法的作用:

 语法:Object obj=new Object();

       Obj.wait();

 作用:让当前线程进入等待状态,没有时间限制,直到被唤醒为止(使用notify()方法);

Notify方法以及noitfyAll方法的作用:

  语法:Object obj=new Object();

        Obj.notify();

 作用:可以唤醒正在等待状态的线程,

 ·noitfyAll();唤醒所有正在等待的线程;

生产者和消费者模式:

 生产者和消费者模式是为了专门解决某个需求的;

 生产和消费需要达成均衡;

:wait和noitfy方法是建立在synchronized线程同步机制基础上的;

posted on 2022-03-18 15:06  Jron*  阅读(17)  评论(0编辑  收藏  举报