黑马程序员_java_多线程总结(下)

来源:互联网 发布:脸部比例测试软件 编辑:程序博客网 时间:2024/05/22 10:58
------- <a href="http://www.itheima.com" target="blank">android培训</a>、<a href="http://www.itheima.com" target="blank">java培训</a>、期待与您交流! ----------




(1)问题产生原理分析
     注意:每个线程有个普通的成员变量Student,创建线程的时候需要先初始化该变量






(2)解决方案
     1、看有没有共享数据
     2、看操作共享数据的语句是不是多条语句
     3、看是不是在多线程的环境中




     最后,把操作共享数据的多条语句用锁 锁起来








所以给两个线程while(true){}中间的内容用加锁






修改线程1和线程2中的代码,做到必须修改完才能读取
线程1:负责修改共享数据
 
package tongxin;


 


public class SetThread extends Thread {


       private Student stu;


 


       public SetThread(Student stu) {


              this.stu = stu;


       }


 


       @Override


       public void run() {


              int i = 0;


 


              while (true) {


                     synchronized (stu) {


                            if (i % 2 == 0) {// 执行%2操作,是为了写入不同的数据,测试在写入过程中,是否影响另一个线程的读取操作


                                   stu.name = "张三";


                                   stu.age = 13;


                            } else {


                                   stu.name = "李四";


                                   stu.age = 14;


                            }


                            i++;


                     }


              }


 


       }


}


 
 
线程2:负责获取共享数据信息
 
package tongxin;


 


public class GetThread extends Thread {


       private Student stu;


       public GetThread(Student stu){


              this.stu = stu;


       }


       @Override


       public void run() {


              while(true){


                     synchronized (stu) {


                            System.out.println(stu);


                     }


              }


       }


}


 
 














五、等待唤醒机制


(1)前提(掌握)
     两个线程共用一把锁,此时可以调用该锁的wait和notify方法,实现等待唤醒机制




(2)IllegalMonitorStateException异常原因及解决办法
     如果当前的线程不是此对象锁的所有者,缺调用该对象的notify(),notify(),wait()方法时抛出该异常
     换句话说就是当前线程中的同步代码块的锁 和 调用这三个方法的锁对象不一致就会报错,例如
     synchronized(Student.class){
          Object.class.notify();
     }




     注意 必须有线程现在自食用Object.class锁
(3)sleep和wait的区别
wait:是Object类的方法,可以不用传递参数,释放锁对象
sleep:是Thread类的静态方法,需要传递参数




(4)以下代码有没有问题
public synchronized void set(String name, int age) {
          if (this.flag) {
               try {
                    Object.class.wait();
               } catch (Exception e) {
               }
          }
          this.name = name;
          this.age = age;




          this.flag = true;
          Object.class.notify();
 }
继续修改代码,做到读一次,写一次
共享数据(学生类)
 
package tongxin;


 


public class Student {


       public String name;


       public int age;


      


       public boolean flag = false;


 


       @Override


       public String toString() {


              return "Student [name=" + name + ", age=" + age + "]";


       }


}


 
 
线程1:负责修改共享数据
 
package tongxin;


 


public class SetThread extends Thread {


       private Student stu;


 


       public SetThread(Student stu) {


              this.stu = stu;


       }


 


       @Override


       public void run() {


              int i = 0;


              while (true) {


                    


                     synchronized (stu) {


                            if(stu.flag){


                                   try {


                                          stu.wait();


                                   } catch (InterruptedException e) {


                                          e.printStackTrace();


                                   }


                            }


                            if (i % 2 == 0) {// 执行%2操作,是为了写入不同的数据,测试在写入过程中,是否影响另一个线程的读取操作


                                   stu.name = "张三";


                                   stu.age = 13;


                            } else {


                                   stu.name = "李四";


                                   stu.age = 14;


                            }


                            i++;


                            stu.flag = true;


                            stu.notify();


                           


                     }


              }


 


       }


}


 
 
线程2:负责获取共享数据信息
 
package tongxin;


 


public class GetThread extends Thread {


       private Student stu;


       public GetThread(Student stu){


              this.stu = stu;


       }


       @Override


       public void run() {


              while(true){


                     synchronized (stu) {


                            if(!stu.flag){


                                   try {


                                          stu.wait();


                                   } catch (InterruptedException e) {


                                          e.printStackTrace();


                                   }


                            }


                            System.out.println(stu);


                            stu.flag = false;


                            stu.notify();


                     }


              }


       }


}


 
 
测试
 
package tongxin;


 


public class Test {


       public static void main(String[] args) {


              //创建共享数据


              Student stu = new Student();


              //创建两个线程,并且让这两个线程同时操作这个共享数据


              GetThread get = new GetThread(stu);


              SetThread set = new SetThread(stu);


             


              get.start();


              set.start();


       }


}


 
 






六、线程的优先级(Thread类中)


(1)线程优先级级别
     线程默认优先级是5。范围是1-10
     Thread.MAX_PRIORITY         //10
     Thread.MIN_PRIORITY         //1
     Thread.NORM_PRIORITY     //5




(2)方法
     public final int getPriority():获取线程优先级
     public final void setPriority(int newPriority):更改线程的优先级




(3)注意
     优先级可以在一定的程度上,让线程获较多的执行机会




(4)举例
     MyThread t = new MyThread();
     System.out.println(t.getPriority());
     t.setPriority(Thread.MAX_PRIORITY);




七、暂停线程(Thread类中)


(1)概述
     暂停当前正在执行的线程,让其他线程执行




(2)成员方法
     public static void yield():暂停当前正在执行的线程对象,并执行其他线程。




(3)注意
     是为了让线程更和谐一些的运行,但是你不要依赖这个方法保证,如果要真正的实现数据依次输出,请使用等待唤醒机制




八、加入线程(Thread类中)


(1)概念
     如果调用一个线程的join方法,那么其他线程必须等待该线程执行完毕后才能执行     




(2)成员方法
     public final void join():等待该线程终止




     线程启动后调用该方法


九、守护线程(Thread类中)






(1)成员方法
     public final void setDaemon(boolean on):设置线程为守护线程,一旦前台(主线程),结束,守护线程就结束了




(2)注意
     main方法就本身是一个线程,我们在main方法里创建线程,并且设置线程为守护线程后,main方法结束后,守护线程就自动结束了

0 0
原创粉丝点击