高洪岩--多线程
来源:互联网 发布:java 加密解密 编辑:程序博客网 时间:2024/05/16 08:36
一、线程状态
1)综述:
线程终止三种方法:
1、使用退出标志,使线程正常退出,也就是当run方法完成线程终止;
2、使用stop方法强行终止线程(不推荐使用),因为stop和suspend及resume数据过期方法,可能产生不可预料结果;
3、使用interrupt方法中断线程
2)概念、案例及实战引入:
Interrupt():该方法使用效果不像for+break,马上停止循环,调用interrupt()仅仅是在当前线程中打一个停止标记,并不真的停止线程。
总结:
(1)this.interrupted():测试当前线程是否已经中断,执行后具有将状态标志清除为false的功能
(2)this.isInterrupted():测试线程是否已经中断,但不清除状态标志
publicclass InterruptThreadextends Thread{
@Override
publicvoid run() {
for(inti = 0 ; i<5000 ;i++){
System.out.println("i==="+i);
//this.interrupt()
//在线程中执行interrupt()都无法终止线程执行
}
}
}
publicstaticvoid main(String[]args) {
InterruptThread td = new InterruptThread();
td.start();
try {
Thread.sleep(2000);
} catch (InterruptedExceptione) {
//TODO Auto-generated catch block
e.printStackTrace();
}
td.interrupt();
}
解析:线程并不会因为interrupt()调用而终止或者卡顿,只会继续执行!
判断线程是否停止状态(this.interrupted 测试当前线程是否已经中断;this.isInterrupted测试线程是否已经中断)
publicclass ThisInterruptedThreadextends Thread{
@Override
publicvoid run() {
for(inti = 0; i<50000 ;i++){
System.out.println("i---->"+i);
}
}
}
publicclass ThisInterruptedThreadRn {
publicstaticvoid main(String[]args) {
ThisInterruptedThread td = new ThisInterruptedThread();
td.start();
try {
Thread.sleep(1000);
} catch (InterruptedExceptione) {
//TODO Auto-generated catch block
e.printStackTrace();
}
td.interrupt();
Thread.currentThread().interrupt();
System.out.println("线程是否终止:"+Thread.interrupted());
//true interrupted只是标识当前线程,也就是主线程终止标志
System.out.println("线程是否终止:"+td.interrupted());
//false interrupted不能获取到子线程结束标志
System.out.println("线程是否终止:"+Thread.interrupted());
//false官方文档解释:如果当前线程连续两次调用interrupted()方法,
//则第一次调用已经清除了中断状态,第二次调用则为false了。
}
}
解析:interrupt()并不能中断线程,同时interruptted()方法只能中断当前所在线程,不能中断其他线程,连续执行时第一次会清除中断的标识。
Break,中断执行(只能中断循环,不能中断线程执行及后续代码执行)
publicclass ExceptionThreadextends Thread{
@Override
publicvoid run() {
for(inti = 0 ; i<5000;i++){
if(this.isInterrupted()){
System.out.println(i+"---------线程可以终止");
break;
}
System.out.println("i-->"+i);
}
System.out.println("线程被interrupt后还能执行该代码");
for(intj =0 ; j<100; j++){
System.out.println("线程break interrupt之后:"+j);
}
}
}
publicclass ExceptionThreadRn {
publicstaticvoid main(String[]args) {
ExceptionThread et = new ExceptionThread();
et.start();
try {
Thread.sleep(10);
} catch (InterruptedExceptione1) {
//TODO Auto-generated catch block
e1.printStackTrace();
}
et.interrupt();
try {
Thread.sleep(1000);
} catch (InterruptedExceptione) {
//TODO Auto-generated catch block
e.printStackTrace();
}
}
}
解析:子线程内通过isInterrupted()判断后,只会中断当前的循环,后续的代码逻辑和再次的一个循环代码还会继续执行。
在沉睡中终止线程:
publicclass SleepThreadextends Thread{
@Override
publicvoid run() {
System.out.println("thread start");
try {
Thread.sleep(1000);
} catch (InterruptedExceptione) {
//TODO Auto-generated catch block
System.out.println("子线程是否被终止:"+this.interrupted());
e.printStackTrace();
}
System.out.println("thread end");
}
}
publicclass SleepThreedRn {
publicstaticvoid main(String[]args) {
SleepThread st = new SleepThread();
st.start();
try {
Thread.sleep(500);
} catch (InterruptedExceptione) {
//TODO Auto-generated catch block
e.printStackTrace();
}
st.interrupt();
}
}
结果:
解析:如果在sleep状态下终止某一个线程,会进入catch操作,并且清除线程终止状态,然后线程状态为false。
线程停止----暴力停止stop
publicclass StopThreadextends Thread{
@Override
publicvoid run() {
inti = 0;
while(i <5999999){
i ++;
System.out.println("当前运行结果:"+i);
}
System.out.println("线程被终止");
}
}
publicclass StopThreadRn {
publicstaticvoid main(String[]args) {
StopThread st = new StopThread();
st.start();
try {
Thread.sleep(500);
} catch (InterruptedExceptione) {
//TODO Auto-generated catch block
e.printStackTrace();
}
st.stop();
}
}
结果:
解析:stop()执行之后,线程立刻中断,不会执行任何代码!同时该方法已经被作废,如果强制线程终止可能有一些清理性工作得不到完成;另外一个就是对锁定的对象进行解锁,导致数据得不到同步处理,出现数据不一致。
数据不一致案例:
publicclass StopTipInfo {
private Stringusernanme ="uaa";
private Stringpassword = "paa";
public String getUsernanme() {
returnusernanme;
}
publicvoid setUsernanme(Stringusernanme) {
this.usernanme =usernanme;
}
public String getPassword() {
returnpassword;
}
publicvoid setPassword(Stringpassword) {
this.password =password;
}
publicsynchronizedvoid printInfo(Stringusername,Stringpassword){
// System.out.println("username = "+username+",password="+password);
this.usernanme =username;
try {
Thread.sleep(5000);
} catch (InterruptedExceptione) {
//TODO Auto-generated catch block
e.printStackTrace();
}
this.password =password;
}
}
publicclassStopTipThread extends Thread{
private StopTipInfostopTipInfo;
public StopTipThread(StopTipInfostopTipInfo){
this.stopTipInfo =stopTipInfo;
}
@Override
publicvoid run() {
stopTipInfo.printInfo("cc","pcc");
}
}
publicclass StopTipInfoRn {
publicstaticvoid main(String[]args) {
StopTipInfo info = new StopTipInfo();
StopTipThread st = new StopTipThread(info);
st.start();
try {
Thread.sleep(500);
} catch (InterruptedExceptione) {
//TODO Auto-generated catch block
e.printStackTrace();
}
st.stop();
System.out.println("username = "+info.getUsernanme()+",password="+info.getPassword());
}
}
结果:username = cc,password=paa
解析:stop()方法导致同步线程数据出现不一致性。
Interrupt()+return;完成线程内部业务中断:
publicclass ReturnThreadextends Thread{
@Override
publicvoid run() {
inti = 0;
while(true){
i ++;
System.out.println("i==>"+i);
if(Thread.interrupted()){
System.out.println("线程停止----");
return ;
}
System.out.println("---->");
}
}
}
publicclass ReturnThreadRn {
publicstaticvoid main(String[]args) {
ReturnThread rt = new ReturnThread();
rt.start();
try {
Thread.sleep(100);
} catch (InterruptedExceptione) {
//TODO Auto-generated catch block
e.printStackTrace();
}
rt.interrupt();
}
}
解析:实现子线程中断,后续业务不再持续进行;建议使用异常抛出手段来解决子线程中断问题。
二、多线程变量并发访问
案例一:成员变量(实例变量)和普通(方法内)变量区别
publicclass HasSelfPrivateNum {
privateintindex = -1;//成员变量
publicvoid addI(Stringusername){
try {
intnum = 0;//方法内变量
if(username.equals("a")){
num = 100;
index = 1111;
System.out.println("a is set over 100");
Thread.sleep(2500);
}else{
num = 200;
index = 222;
System.out.println("b is set over 200");
}
System.out.println("username = "+username +",num = "+num+"---->index="+index);
} catch (Exceptione) {
thrownew RuntimeException(e);
}
}
}
publicclass ThreadAextends Thread{
private HasSelfPrivateNumhas;
public ThreadA(HasSelfPrivateNumhas){
this.has =has;
}
@Override
publicvoid run() {
has.addI("a");
}
}
publicclass ThreadBextends Thread {
privateHasSelfPrivateNum has;
public ThreadB(HasSelfPrivateNumhas){
this.has =has;
}
@Override
publicvoid run() {
this.has.addI("b");
}
}
publicclass HasSelfPrivateNumRn {
publicstaticvoid main(String[]args) {
HasSelfPrivateNum has = new HasSelfPrivateNum();
ThreadA a = new ThreadA(has);
ThreadB b = new ThreadB(has);
a.start();
b.start();
}
}
结果:
解析:因为方法内都是各自线程自我调用,没有共同资源;成员变量出现了(公共资源),因为线程共同访问+沉睡,导致了错误,同时多线程的调用导致了整个打印的错乱。
-------
案例二:方法级别同步,保证线程安全性
修改:在HasSelfPrivateNum类中的addI()方法加上synchronized关键字,产生正确结果(同时造成线程的堵塞)。多个线程同时持有一个对象的锁,看线程强占速度,所以日志没有交叉,数据正确。
结果【实现线程安全】:
案例三:多个对象多个锁
publicclass HasSelfPrivateNumRn2 {
publicstaticvoid main(String[]args) {
HasSelfPrivateNum t1 = new HasSelfPrivateNum();
HasSelfPrivateNum t2 = new HasSelfPrivateNum();
ThreadA a = new ThreadA(t1);
ThreadB b = new ThreadB(t2);
a.start();
b.start();
}
}
结果:
解析:声明了t1和t2两个对象,在a线程中调取t1对象,拥有的是t1对象的锁,而b线程中调取t2对象,拥有的是t2对象的锁。关键字synchronized取得的锁都是对象锁,这样他们就互不影响,t1和t2的信息都保存在自己的线程栈中,对其他线程不可见,所有a和b并发执行(log交叉)。
案例四:类锁【继续修改上述案例】
publicclass HasSelfPrivateNum {
privatestaticintindex = -1;//静态化
//方法静态化
publicstaticsynchronizedvoid addI(String username){
try {
intnum = 0;
if(username.equals("a")){
num = 100;
index = 1111;
System.out.println("a is set over 100");
Thread.sleep(2500);
}else{
num = 200;
index = 222;
System.out.println("b is set over 200");
}
System.out.println("username = "+username +",num = "+num+"---->index="+index);
} catch (Exceptione) {
thrownew RuntimeException(e);
}
}
}
结果:
解析:如果在addI方法上加上static关键字,,表示锁定class类。不管声明多少个MultiThread引用,printNum方法跟随类存放在堆上,线程间会共享资源,输出结果会等m1信息输出结束之后才会开始输出m2信息。
总结:一个对象一把锁(实现对象上互斥);在静态方法上synchronized代表的是类的锁(实现类上互斥)。
案例五:
publicclass ThreeSynchronizedTask {
publicsynchronizedvoid printA(){
System.out.println(Thread.currentThread().getName()+"--printA--"+System.currentTimeMillis());
}
publicsynchronizedvoid printB(){
try {
Thread.sleep(2000);
} catch (InterruptedExceptione) {
//TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"--printB--"+System.currentTimeMillis());
}
publicsynchronizedvoid printC(){
System.out.println(Thread.currentThread().getName()+"--printC--"+System.currentTimeMillis());
}
}
publicclass Taextends Thread{
private ThreeSynchronizedTasktask;
public Ta(ThreeSynchronizedTasktask){
this.task =task;
}
@Override
publicvoid run() {
task.printA();
task.printB();
task.printC();
}
}
publicclass Tbextends Thread{
private ThreeSynchronizedTasktask;
public Tb(ThreeSynchronizedTasktask){
this.task =task;
}
@Override
publicvoid run() {
task.printA();
task.printB();
task.printC();
}
}
publicclass ThreeSynchronizedTaskRn {
publicstaticvoid main(String[]args) {
ThreeSynchronizedTasktask = newThreeSynchronizedTask();
Ta a = new Ta(task);
a.setName("A");
Tb b = new Tb(task);
b.setName("B");
a.start();
b.start();
}
}
结果:
解析:
线程强占锁之后,执行synchronized方法,然后如果有持续的synchronized方法会继续持有,否则释放掉抢占的锁。也会出现线程交替执行的程序。
三、volatile关键字
作用:用户多个线程之间实现修饰符变量可见。
- 高洪岩--多线程
- 多线程
- 多线程
- 多线程
- 多线程
- 多线程
- 多线程
- 多线程
- 多线程
- 多线程
- 多线程
- 多线程
- 多线程
- 多线程
- 多线程
- 多线程
- 多线程
- 多线程
- 听见丨朱啸虎回应ofo摩拜是否合并:战局明朗再打就没意义了 微软谷歌曾私下表达反对博通收购高通,害怕苹果更强
- 无人便利店风口盛起,谁是最后赢家?
- Hive权限管理:
- 学习这些设计模式,让你写出更优雅的代码
- 后勤常用查询报告
- 高洪岩--多线程
- Android手机像素dp问题
- 12月2日笔记
- Netty实践
- 数据库迁移必备--迁移登录账户
- 171211之Oracle定时任务
- https://zhidao.baidu.com/question/1544472571741441987.html
- Android app 与网页交互 WebView 与JS交互
- MinGW与Cygwin 的区别