java语法知识之多线程初解析

多线程

1、一块CPU同一时间只能执行一条指令,一个进程允许有多个线程,故多线程之间的交替执行的。

2、创建多线程的两种方法。

 一、使用Thread类
     实现方法:
     1、写子类继承Thread类,并重写run方法。
     2、调用start()方法(继承thread类),此方法可以产生一个新线程并在此线程基础上调用run()方法
     注意:一个Thread类对象代表一个线程,并且只能代表一个线程;
     Thread.currentThread()静态方法可获得该代码当前执行时对应的那个线程对象。 getName()方法可获得线程对象名称。
            
 二、使用Runnable接口
     实现方法:
     1、创建新的类实现Runnable接口,并实现接口里的run方法。
     2、实例化该新类。
     3、实例化Thread类,并将上一步创建的对象作为参数传入thread类的构造方法。
     注:可实例化一次新类,然后多次调用start()方法来产生多线程。

3、关于线程的多种操作

  一、后台线程
     在调用start()方法前调用setDaemon(true)方法,可将此前台程序转为后台,当前台线程结束时,后台线程也随之结束,因为延迟问题后台线程往往还会运行一小段时间才关闭
  
  二、联合线程
     join()方法可以合并当前线程到到调用这句话之前的线程中去,Thread类中的成员方法,让调用join()方法的线程处于等待状态,直到子线程执行结束,join()方法通常由使用线程的程序调用,用于将一个线程拆分成若干小的线程执行,执行结束最后由主线程进行进一步的操作
     join(long millis),join(long millis,int nanos)这两个方法可将两个线程合并指定的时间后再分离回到之前的状态(后者一般不用)。前者精确至毫秒,后者精确至纳秒。   
     
  三、传递数据
     方法一、如果是用Thread或者其子类写多线程,可在该类中重写一个带参数的构造方法,通过该构造方法向线程中传入数据
     方法二、如果是新建类实现Runnable接口,可在该类中实现setValue方法然后调用方法传入数据。也可以先在类中调用一系列public的方法或变量然后创建对象挨个赋值。
  
  四、返回数据
     1、可在线程结束后通过类变量或者方法得到数据
     2、Thread.start()方法后添加sleep(runtime),延迟主线程一段时间,也可以添加Thread.join()语句使线程变成同步执行,此时与普通方法得到返回数据类似,后面可以再使用ReturnThread类的任何资源来返回数据。
     
  五、线程休眠与让步
     调用thread.sleep()静态方法,可以让当前线程休眠一定时间进入阻塞状态再运行,同时会抛出InterruptedExextion异常!
  
     调用Thrad类的静态方法 yield()方法可以实现线程让步,和sleep()方法类似,yield()方法也是让当前正在运行的线程暂停,但是不会使线程阻塞,而是让线程进入就绪状态,让线程调度器重新安排一次线程调度,完全有可能出现的状况是,刚刚调用yield()方法进入就绪状态的线程就被线程调度器重新调度出来重新执行。
  注意:
     1.线程调用yield()方法后将执行的机会让给优先级相同的线程
     2.高优先级的线程调用yield()方法暂停之后,系统中没有与之相同优先级和更高的优先级的线程,则线程调度器会将该线程重新调度出来,重新执行。
  六、线程优先级
    1.一般线程具有优先级,更高优先级的线程比优先级低的线程能获得更多的执行机会
    2.每个线程默认的优先级和创建他们的父线程的优先级相同。
    3.Thread类提供了setPriorit(int newPriority)、getPriority() 方法来设置和获取线程的优先级
    4.也可以使用Thread类的3个静态常量来设置线程的优先级:
    MAX_PRIORITY : 值是10
    MIN_PRIORIT : 值是1
    NORM_PRIORITY : 值是5

4、线程同步

1、线程安全性问题
原子性:即在一个线程运行到if类循环判断语句时,CPU不去执行其它可能影响当前线程执行结果的代码块,CPU必须等到该线程的下一条语句运行完之后再去执行其它线程的相关代码

实现方式:
一、通过synchronized关键字同步代码块

 synchronized(objectReference){
                 代码块;
                 }
       objectreFerence可以是任意一个对象,包括字符串。
       一个用于synchronized语句的对象称为一个监视器,当一个线程获得了此语句内代码块的执行权时,意味着锁定了监视器,同步处理后,程序运行速度会减慢,因为系统不断地对同步监视器进行检查

二、通过synchronized关键字同步函数

      synchronized 方法名(){
                代码块;
                }

三、通过this监视器对象来同步代码块与函数

          synchronized(this){
                 代码块;
                 }
 此时同步函数与同步代码块使用的监视器对象为同一个
 注意:同步主要解决当多个线程共享数据时,必须防止一个线程对共享数据仅仅进行了部分操作就退出的情况出现,这会破坏数据一致性.共享数据时,应当是类的private数据成员

四、线程的死锁

两个线程对两个同步对象具有循环依赖时,即两个线程互相等待对方已被锁定的资源形成了死锁,这种情况应尽量避免

5、线程的生命周期与周期控制

新建状态;使用new关键字,Thread类或其子类建立一个线程对象后,该对象便处于新建状态,处于新建状态的线程有自己的内存空间,通过调用start方法进入就绪状态

就绪状态:处于就绪状态的线程已经具备了运行条件,因为在等待CPU调度(即CPU挑选等待队列的线程,并使其进入可执行状态),此时处于线程就绪队列,虽然此时位于等待队列,当CPU调度不一定是按先进先出的顺序来的,故称可运行池更合适。一旦进入运行状态获得CPU资源便会自行调用自己的run方法。

运行状态:

1、如果该线程失去了CPU资源,就会再次进入就绪状态,等待CPU调度,也可以使用yield方法,让出CPU资源,再次进入就绪状态
2、如果进行下列操作将进入阻塞状态:
	调用sleep方法,将主动放弃CPU资源;
	调用一个阻塞式IO方法,在该方法返回之前,该线程将被阻塞;
	线程正在等待某个通知(notify);
	调用suspend方法将线程挂起,此方法易导致死锁,不推荐使用;
3、当run方法执行完,或者被强制性终止,例如出现异常,或者调用了stop(),destory()方法等,就会从运行状态转变为死亡状态

阻塞状态:在阻塞状态的线程不能进入就绪状态,只有当引起阻塞的原因消除时才能进入就绪状态,在经CPU调度后再次从原来停止的位置开始继续运行

死亡状态:当run方法执行完,或者被强制性终止,就认为它已死去,也许线程对象是活的,当已经不是一个可以单独执行的线程,线程一旦死亡便不能复生,再次在死亡的异常上调用start方法会抛出异常

6、线程通信

即线程间的消息传递
wait(),noyify(),notifyAll()方法可实现通信,并且被所有的类默认拥有,但是只有在synchronized关键字作用的范围内,并且是同一个同步问题中才有意义,在Object类中的语法格式

final void wait()throws InterruptedException
final void notify()
final void notifyAll()

调用wait ()方法可以时调用该方法的线程释放共享的CPU资源的锁,然后从运行状态退出,进入等待队列,直到再次被唤醒。
调用notify()方法可以唤醒队列中第一个等待同一共享资源的线程,并使该线程退出等待队列,进入可运行状态。(而调用notifyAll()方法可以唤醒所有正在等待的线程,此时优先级最高的最先唤醒)
注意:使用wait()方法时,会被声明抛出InterruptedException异常,故需要做异常处理,并将其放入一个同步代码段中,否则还会抛出异常

发布了7 篇原创文章 · 获赞 1 · 访问量 130

猜你喜欢

转载自blog.csdn.net/weixin_43694216/article/details/104450032