Java多线程技能。

多线程是异步的,所以千万不要把Eclipse里代码的顺序当成线程执行的顺序,线程被调用的时机是随机的。

使用多线程

继承Thread类

  • 使用多线程技术时,代码的运行结果与代码执行顺序或调用顺序是无关的。
  • Thread.java类中的start()方法通知“线程规划器”此线程已经准备就绪,等待调用线程对象的run()方法。这个过程其实就是让系统安排一个时间来调用Thread中的run()方法,也就是使线程得到运行,启动线程,具有异步执行的效果。如果调用代码thread.run()就不是异步执行了,而是同步,那么此线程对象并不交给“线程规划器”来进行处理,而是由main主线程来调用main()方法,也就是必须等run()方法中的代码执行后面的代码。
  • 执行start()方法的顺序不代表线程启动的顺序。

实现Runnable接口

实例变量与线程安全

  • 非线程安全主要是指多个线程对同一个对象中的同一个实例变量进行操作时会出现值被更改、值不同步的情况,进而影响程序的执行流程。

留意i--与System.out.println()的异常

currentThread()方法

  • currentThread()方法可返回代码段正在被哪个线程调用的信息。

isAlive()方法

  • 方法isAlive()的作用是测试线程是否处于活动状态。什么是活动状态呢?活动状态就是线程已经启动且尚未终止。线程处于正在运行或准备开始运行的状态,就认为线程是“存活”的。
  • 在使用isAlive()方法,如果将线程对象以构造参数的方式传递给Thread对象进行start()启动时,运行结果是有差异的。造成这样的差异的原因还是来自于Thread.currentThread()和this的差异。

sleep()方法

  • 方法sleep()的作用是在指定的毫秒数内让当前“正在执行的线程”休眠(暂停执行)。这个“正在执行的线程”是指this.currentThread()返回的线程。

getId()方法

  • getId()方法的作用就是取得线程的唯一标识。

停止线程

  • 大多数停止一个线程的操作使用Thread.interrupt()方法,尽管方法的名称是“停止,中止”的意思,但这个方法不会终止一个正在运行的线程,还需要加入一个判断才可以完成线程的停止。
  • 在java中有以下3种方法可以终止正在运行的线程:

          使用退出标志,使线程正常退出,也就是当run方法完成后线程终止。

         使用stop方法强行终止线程,但是不推荐使用这个方法,因为stop和suspend及resume一样,都是作废过期的方法,使 用他们可能产生不可预料的结果。

          使用interrupt方法中断线程。

停止不了的线程

  • 调用interrupt()方法仅仅是在当前线程中打了一个停止的标记,并不是真的停止线程。

判断线程是否是停止状态

  • this.interrupted():测试当前线程是否已经是中断状态,执行后具有将状态标志置清除为false的功能。
  • this.isInterrupted():测试线程Thread对象是否已经是中断状态,但不清楚状态标志。

能停止的线程——异常法

在沉睡中停止(sleep)

能停止的线程——暴力停止(stop)

方法stop()与java.lang.ThreadDeath异常

  • 方法stop()已经被作废,因为如果强制让线程停止则有可能使一些清理性的工作得不到完成。另外一个情况就是对锁定的对象进行了“解锁”,导致数据得不到同步的处理,出现数据不一致的问题。

释放锁的不良后果

  • 使用stop()释放锁将会给数据造成不一致的结果。

使用return停止线程

  • 将方法interrupt()与return结合使用也能实现停止线程的效果。
  • 建议使用“抛异常”法来实现线程的停止,因为在catch块中可以对异常的信息进行相关的处理,而且使用异常流能更好、更方便的控制程序的运行流程,不至于代码中出现很多个return;造成污染。

暂停线程

  • 暂停线程意味着此线程还可以恢复运行。在Java多线程中,可以使用suspend()方法暂停线程,使用resume()方法恢复线程的执行。

suspend与resume方法的使用

suspend与resume方法的缺点——独占

  • 在使用suspend与resume方法时,如果使用不当,极易造成公共的同步对象的独占,使得其他线程无法访问公共同步对象。
  • 独占锁的情况也要格外注意,稍有不慎,就会掉进“坑”里。
  • 当程序运行到println()方法内部停止时,同步锁未被释放。

suspend与resume方法的缺点——不同步

yield方法

  • yield()方法的作用是放弃当前的CPU资源,将他让给其他的任务去占用CPU执行时间。但放弃的时间不确定,有可能刚刚放弃,马上又获得CPU时间片。

线程的优先级

  • 设置线程的优先级使用setPriority()方法

线程优先级的继承特性

优先级具有规则性

  • 高级优先级的线程总是大部分先执行完,但不代表高优先级的线程全部先执行完。
  • 当线程优先级的等级差距很大时,谁先执行完和代码的调用顺序无关。
  • 线程的优先级具有一定的规则性,也就是CPU尽量将执行资源让给优先级比较高的线程。

优先级具有随机性

  • 不要把线程的优先级与运行结果的顺序作为衡量的标准,优先级较高的线程并不一定每一次都先执行完run()方法中的任务,也就是说,线程优先级与打印顺序无关,不要将这两者的关系相关联,他们的关系具有不确定性和随机性。

看谁运行的快

守护进程(Daemon)

  • 守护线程的作用是为其他线程的运行提供便利服务,最典型的应用就是GC(垃圾收集器)。

猜你喜欢

转载自blog.csdn.net/en_joker/article/details/80433410