高洪岩--多线程

来源:互联网 发布:java 加密解密 编辑:程序博客网 时间:2024/05/16 08:36

一、线程状态

1)综述:

线程终止三种方法:

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

2、使用stop方法强行终止线程(不推荐使用),因为stop和suspend及resume数据过期方法,可能产生不可预料结果;

3、使用interrupt方法中断线程

 

2)概念、案例及实战引入:

Interrupt():该方法使用效果不像for+break,马上停止循环,调用interrupt()仅仅是在当前线程中打一个停止标记,并不真的停止线程。

总结:

1this.interrupted():测试当前线程是否已经中断,执行后具有将状态标志清除为false的功能

2this.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();

   }

}

结果:

解析:声明了t1t2两个对象,在a线程中调取t1对象,拥有的是t1对象的锁,而b线程中调取t2对象,拥有的是t2对象的锁。关键字synchronized取得的锁都是对象锁,这样他们就互不影响,t1t2的信息都保存在自己的线程栈中,对其他线程不可见,所有ab并发执行(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关键字

作用:用户多个线程之间实现修饰符变量可见。

 

原创粉丝点击