停止线程
停止线程是在多线程开发时很重要的技术点,掌握此技术可以对线程的停止进行有效的处理。
停止一个线程可以使用Thread.stop()方法,但最好不用它。该方法是不安全的,已被弃用。
在Java中有以下3种方法可以终止正在运行的线程:
- 使用退出标志,使线程正常退出,也就是当run方法完成后线程终止
- 使用stop方法强行终止线程,但是不推荐使用这个方法,因为stop和suspend及resume一样,都是作废过期的方法,使用他们可能产生不可预料的结果。
- 使用interrupt方法中断线程,但这个不会终止一个正在运行的线程,还需要加入一个判断才可以完成线程的停止。
暂停线程
interrupt()方法
线程的优先级
在操作系统中,线程可以划分优先级,优先级较高的线程得到的CPU资源较多,也就是CPU优先执行优先级较高的线程对象中的任务。
设置线程优先级有助于帮“线程规划器”确定在下一次选择哪一个线程来优先执行。
设置线程的优先级使用setPriority()方法,此方法在JDK的源码如下:
public final void setPriority(int newPriority) { ThreadGroup g; checkAccess(); if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) { throw new IllegalArgumentException(); } if((g = getThreadGroup()) != null) { if (newPriority > g.getMaxPriority()) { newPriority = g.getMaxPriority(); } setPriority0(priority = newPriority); } }
在Java中,线程的优先级分为1~10这10个等级,如果小于1或大于10,则JDK抛出异常throw new IllegalArgumentException()。
JDK中使用3个常量来预置定义优先级的值,代码如下:
public final static int MIN_PRIORITY = 1; public final static int NORM_PRIORITY = 5; public final static int MAX_PRIORITY = 10;
线程优先级特性:
- 继承性
比如A线程启动B线程,则B线程的优先级与A是一样的。 - 规则性
高优先级的线程总是大部分先执行完,但不代表高优先级线程全部先执行完。 - 随机性
优先级较高的线程不一定每一次都先执行完。
守护线程
在Java线程中有两种线程,一种是User Thread(用户线程),另一种是Daemon Thread(守护线程)。
Daemon的作用是为其他线程的运行提供服务,比如说GC线程。其实User Thread线程和Daemon Thread守护线程本质上来说去没啥区别的,唯一的区别之处就在虚拟机的离开:如果User Thread全部撤离,那么Daemon Thread也就没啥线程好服务的了,所以虚拟机也就退出了。
守护线程并非虚拟机内部可以提供,用户也可以自行的设定守护线程,方法:public final void setDaemon(boolean on) ;但是有几点需要注意:
- thread.setDaemon(true)必须在thread.start()之前设置,否则会跑出一个IllegalThreadStateException异常。你不能把正在运行的常规线程设置为守护线程。 (备注:这点与守护进程有着明显的区别,守护进程是创建后,让进程摆脱原会话的控制+让进程摆脱原进程组的控制+让进程摆脱原控制终端的控制;所以说寄托于虚拟机的语言机制跟系统级语言有着本质上面的区别)
- 在Daemon线程中产生的新线程也是Daemon的。 (这一点又是有着本质的区别了:守护进程fork()出来的子进程不再是守护进程,尽管它把父进程的进程相关信息复制过去了,但是子进程的进程的父进程不是init进程,所谓的守护进程本质上说就是“父进程挂掉,init收养,然后文件0,1,2都是/dev/null,当前目录到/”)
- 不是所有的应用都可以分配给Daemon线程来进行服务,比如读写操作或者计算逻辑。因为在Daemon Thread还没来的及进行操作时,虚拟机可能已经退出了。
同步与死锁
- 同步代码块
在代码块上加上”synchronized”关键字,则此代码块就称为同步代码块 - 同步代码块格式
1 synchronized(同步对象){ 2 //需要同步的代码块; 3 }
- 同步方法
除了代码块可以同步,方法也是可以同步的 - 方法同步格式
synchronized void 方法名称(){}