java多线程编程技术chapter1
Thread类的核心方法较多
1.线程的启动
2.如何线程暂停
3.如何线程停止
4.线程的优先级
5.线程安全相关的问题
进程的概念
进程是操作系统结构的基础,是一次程序的执行,是一个程序及其数据在处理机上顺序执行时所发生的活动,是程序在一个数据集合上运行的过程,它是系统进行资源分配和调度的一个独立单位
进程是受操作系统管理的基本运行单元。
线程
线程可以理解成是在进程中独立运行的子任务,比如QQ.exe运行时有很多子任务在运行
单任务的特点就是排队执行,也就是同步
使用多线程也就是在使用异步,线程被调用的时机是随机的
参照程序:SimpleThread\src\com\nineclient\call\chapter1\a\MainThread.java
控制台输出的main实际上是一个名称叫做main的线程在执行main()方法中的代码
实现多线程编程的方式主要有两种:一种是继承Thread类,另一种是实现Runnable接口
public
class
Thread
implements
Runnable
Thread类和Runnable接口之间有多态关系,本质是一样的
继承Thread类的方式最大的局限就是不支持多继承
为了支持多继承,可以实现Runnable
参照代码:SimpleThread\src\com\nineclient\call\chapter1\a\MyThread.java
使用多线程技术时,代码的运行结果与代码的执行顺序或调用顺序是无关的
多次调用start();
参照代码:
SimpleThread\test\com\nineclient\call\chapter1\a\TestMyThread.java
报错
Exception in thread "main"
MyThread
java.lang.IllegalThreadStateException
at java.lang.Thread.start(
Thread.java:705
)
at com.nineclient.call.Run.main(
Run.java:7
)
随机特性,线程启动的随机性
参照代码:SimpleThread\src\com\nineclient\call\chapter1\b\MyThread1.java
可以看出,CPU执行哪个线程具有不确定性
Thread类中的start方法通知线程规划器,此线程已经准备就绪,等待调用线程对象的run方法,这个过程其实是让系统安排一个时间来调用Thread中的run方法,使线程得到运行,启动线程,异步执行
如果调用thread.run方法就不是异步执行,而是同步,那么此线程对象并不交给线程规划器来进行处理,而是由main主线程来调用run方法。必须等run方法中代码执行完才可以执行后面的代码。
执行start的顺序不代表线程启动的顺序
参照代码:SimpleThread\src\com\nineclient\call\chapter1\c\MyThread2.java
如果要创建的线程类已经有一个类了,这时就不能再继承Thread类了,就需要实现Runnable接口
参照代码:SimpleThread\src\com\nineclient\call\chapter1\d\MyRunnable.java
因为Thread类也实现了Runnable接口,意味着构造函数不光可以传入Runnable接口的对象,还可以传入一个Thread类的对象,这样可以将一个Thread的run方法交给其他的线程进行调用
参照代码:SimpleThread\src\com\nineclient\call\chapter1\e\MyThreadThread.java
线程数据不共享,每个线程都是各种的count单独执行
参照代码:SimpleThread\src\com\nineclient\call\chapter1\f\MyThread5.java
线程数据共享,多个线程共同对一个count变量进行操作
有两种:代码里都有
参照代码:SimpleThread\src\com\nineclient\call\chapter1\g\MyThread6.java
上面的数据共享会出现线程不安全的问题,这时候就需要使多个线程之间进行同步,也就是按顺序排队的方式进行减一操作
参照代码:SimpleThread\src\com\nineclient\call\chapter1\g\MyThread6.java
通过在run方法前面加入synchronized关键字,使多个线程在执行run方法时,以排队的方式进行处理,当一个线程调用run方法时,先判断run方法有没有被上锁,synchronized可以在任意对象及方法上加锁
非线程安全是指多个线程对同一个对象中的同一个实例变量进行操作时出现值被更改,值不同步的情况,进而影响程序的执行流程
举例说明,模拟登陆场景
参照代码:
SimpleThread\src\com\nineclient\call\chapter1\threadsafe\LoginServlet.java
SimpleThread\src\com\nineclient\call\chapter1\threadsafe\Run.java
currentThread()
返回代码段正在被哪个线程调用的信息
MyThread.java类的构造函数是被main线程调用的
run方法是被Thread-0线程调用的,run方法是自调用的方法
myThread.run()是被main线程调用的
this.getName(),this指的是当前对象在Thread类中被调用返回的是线程名
参照代码:SimpleThread\src\com\nineclient\call\chapter1\countoperate\CountOperate.java
isAlive()
判断当前的线程是否处于活动状态
参照代码:SimpleThread\src\com\nineclient\call\chapter1\isalive\Live.java
start方法开始之前,都是false,start方法开始到run方法运行结束都是true
sleep()
作用是让当前正在执行的线程休眠,这个正在执行的线程指的是this.currerntThread()返回的线程
参照代码:SimpleThread\src\com\nineclient\call\chapter1\sleep\Sleep.java
getId()方法
取得线程的唯一标识
停止线程
掌握此技术可以对线程的停止进行有效的处理
不推荐线程不安全的Thread.stop方法
1.使用退出标识,使线程正常退出,也就是当run方法完成后线程终止
2.不推荐stop,suspend,resume,它们会产生不会预料的结果
3.使用interrupt方法中断线程
调用Interrupt方法仅仅是在当前线程中加了一个停止标记,并不是真正的停止线程
程序照常执行,照常输出
参照代码:SimpleThread\src\com\nineclient\call\chapter1\interrupt\Interrupt.java
this.interrupted()测试当前线程是否已经中断,测试的是运行this.interrupted()的线程,即当前线程main
参照代码:SimpleThread\src\com\nineclient\call\chapter1\interrupted
如何中断main线程呢,当连续调用两次interrupted的时候,会清除状态标志
参照代码:SimpleThread\src\com\nineclient\call\chapter1\main\MainInterrupted.java
this.isInterrupted测试线程是否已经中断,不清除状态
参照代码:SimpleThread\src\com\nineclient\call\chapter1\isinterrupted\IsInterrupted.java
用异常法停止线程
if
(
this
.
interrupted
()
) {
System.
out
.println(
"已经是停止状态了 我要退出了"
);
break
;
}
参照代码:SimpleThread\src\com\nineclient\call\chapter1\interrupted\InterruptedException.java
在沉睡中停止
当线程正在Thread.sleep()的时候,调用interrupted(),会报异常
参照代码:SimpleThread\src\com\nineclient\call\chapter1\interrupted\SleepInterrupted.java
java.lang.InterruptedException
: sleep interrupted
at java.lang.Thread.sleep(
Native Method
)
at com.nineclient.call.chapter1.interrupted.MyThread2.run(
InterruptedSleep.java:19
)
当被中断之后,在调用Thread.sleep(),同样会报异常
参照代码:SimpleThread\src\com\nineclient\call\chapter1\interrupted\SleepInterrupted.java
run begin
java.lang.InterruptedException
: sleep interrupted
at java.lang.Thread.sleep(
Native Method
)
at com.nineclient.call.chapter1.interrupted.MyThread3.run(
SleepInterrupted.java:21
)
使用stop方法停止线程是非常暴力的
不推荐
参照代码:SimpleThread\src\com\nineclient\call\chapter1\stop\MainUseStop.java
参照代码:SimpleThread\src\com\nineclient\call\chapter1\stop\RunUseStop.java
调用stop方法会抛出ThreadDeath异常,通常不需要显示捕捉
java.lang.ThreadDeath
at java.lang.Thread.stop(
Thread.java:813
)
at com.nineclient.call.chapter1.stop.MyThread1.run(
RunUseStop.java:16
)
stop方法过于暴力,导致一些清理性的工作得不到完成,另一种情况就是对对象进行了解锁操作,导致数据得不到同步处理,出现数据不一致
参照代码:SimpleThread\src\com\nineclient\call\chapter1\stop\ObjectStop.java
使用return停止线程,不推荐推荐使用异常结束线程
参照代码:SimpleThread\src\com\nineclient\call\chapter1\isinterrupted\ReturnThread.java
暂停线程suspend()和恢复线程resume()
参照代码:SimpleThread\src\com\nineclient\call\chapter1\suspendresume\SuspendResume.java
线程的确被暂停了,还可以恢复成运行状态
suspend 和 resume 缺点
缺点1,如果使用不当,极易造成公共的同步对象的独占,使得其他线程无法访问公共同步对象
参照代码:SimpleThread\src\com\nineclient\call\chapter1\suspendresume\SuspendResumeLock.java
是系统自带的一些线程安全的对象容易被挂起
参照代码:SimpleThread\src\com\nineclient\call\chapter1\suspendresume\SuspendResumePrintIn.java
缺点2 不同步
SimpleThread\src\com\nineclient\call\chapter1\suspendresume\NoSynchronized.java
yield方法
放弃当前的CPU资源,将它让给其他的任务去占用CPU执行时间,放弃的时间不确定,有可能刚刚放弃,马上又获得CPU时间片
参照代码:SimpleThread\src\com\nineclient\call\chapter1\yield\Yield.java
线程优先级setPriority()
线程的优先级具有继承性,比如A线程启动了B线程,则B线程的优先级和A线程是一样的
优先级具有一定的规则性,也就是尽量将执行资源让给优先级比较高的线程。
守护线程
Daemon
当进程中不存在需要守护的线程了,守护线程自动销毁,垃圾回收线程是典型的守护线程
参照代码:SimpleThread\src\com\nineclient\call\chapter1\daemon\DaemonThread.java
参照代码下载链接:
http://download.youkuaiyun.com/download/qq_15914047/10031138