上一节讲到多线程的创建,两种创建方式一种继承Thread类,一种实现Runnable接口;
常用的多线程函数:
- currentThread()方法 返回代码段正在被哪个线程调用的信息
- isAlive()方法 判断当前线程是否处于活动状态(线程正在运行或准备开始运行的状态)
- sleep()方法 让正在执行的线程休眠(停止执行),这个进程指的是this.currentThread返回的线程
- getId()方法 取得线程的唯一标识
- yield()方法 暂时放弃cpu资源,将cpu资源让给其他程序,但是放弃的时间不确定,可能刚放弃马上又执行
- interrupt()方法 在当前线程中打一个停止标记,不会停止线程
- interrupted()方法 测试当前线程是否已经中断,如果已经中断,则将状态标志清除,并设置为false。(线程的中断状态由该方法清除)
- isInterrupted()方法 测试线程是否已经中断,但不清除状态标志
- setPriority()方法 设置线程的优先级,java中线程优先级分为1-10级,线程的优先级具有继承性。高优先级的线程总是大部分先完成。
既然有创建线程的方法,肯定有停止线程的方法,停止线程的方法主要有3种:
- 使用退出标志,使线程正常退出,也就是run()方法完成时,线程停止
- 使用stop方法强行停止线程,但是这个是已经作废的方法,现在不再使用了
- 使用interrupt方法中断线程
总结写在前面:停止线程的方法最好用的1.break return 跳出 2.try catch跳出
1.使用退出标志
和前面的方法6,7,8的描述一样,退出标志并不能使线程停止,只是给线程打上了一个停止标志,7,8是检查停止标志的方法。
2.使用stop方法强行停止线程
方法已作废,不做讨论
3.interrupt方法中断线程
PlanA---通过
if(this.interrupted()){ System.out.println("已经是停止状态了,我要退出了!"); break; }
使用 if 结合 break 来中断线程,但是他不能干净得结束run方法,因为break仅仅是跳出循环的操作,如果run()方法除了for循环后面还有别的操作,代码是会仅仅跳出for循环而继续执行后面的代码的。
PlanB---通过
try{ for(int I = 0;I < 5000 ; I++){ if(this.interrupted()){ System.out.println("Out!"); throw new InterruptedException(); } } }catch(InterruptedException e){ System.out.println("End"); e.printStackTrace(); }
try-catch 可以通过捕获一场的方式,将整个run()方法放进 try 代码块,通过捕获 interrupt 的状态标志来抛出异常,跳出线程,达到终止线程的目的。
PlanC--通过
if(this.interrupted()){ System.out.println("Is End!"); return; }
通过使用 return 也可以跳出线程
但是通常建议使用抛异常的方式来实现线程的停止,因为在catch块中还可以将异常上抛,使线程停止的事件得以传播。
本节开始涉及到线程安全的问题,因为线程轮流占有CPU运行,当多个线程同时对一个变量进行操作是,会产生脏读的现象。
百度上的脏读是:脏读就是指当一个事物正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据,那么另外一个事务读到的这个数据是脏数据,依据脏数据所做的操作可能是不正确的。------ 多线程下的对数据的操作也会出现同样的场景。(值被更改,值不同步)
为了避免出现以上的现象,多线程会引入 互斥区/临界区 的概念,通过对需要保护的数据(类/对象/方法)加锁,实现互斥的效果,达到线程的安全。
java多线程加锁,主要是通过synchronized关键字与volatile关键字,在下一节里详细写。