黑马程序员——多线程(二)

来源:互联网 发布:淘宝宝贝被删除怎么办 编辑:程序博客网 时间:2024/05/27 09:48

-----------android培训java培训、java学习型技术博客、期待与您交流!------------ 

1、死锁

  死锁产生的原因:一个所中还有另外一个锁,但是这两个锁对象是不相同的,其中一个锁(A)需要另外一个锁(B),而锁(B)也需要锁(A),这样有时候她们都不会妥协,那么就会产生死锁。

  例子:

class MyLock {

  static Object lockA = new Object();

  static Object lockB = new Object();

}

 

public class DeadLock implements Runnable {

  public boolean flag = true;

 

  public DeadLock(boolean f) {

    this.flag = f;

  }

 

  public void run() {

    if (flag) {

      // while (true) {

      synchronized (MyLock.lockA) {

         System.out.println("ifLockA");

         synchronized (MyLock.lockB) {

           System.out.println("ifLockB");

         }

         // }

      }

    } else {

      // while (true) {

      synchronized (MyLock.lockB) {

         System.out.println("elseLockB");

         synchronized (MyLock.lockA) {

           System.out.println("elseLockA");

         }

         // }

      }

    }

  }

}

public class Text {

  public static void main(String[] agrs) {

    DeadLock l1 = new DeadLock(true);// 第一个线程

    DeadLock l2 = new DeadLock(false);// 第二个线程

    new Thread(l1).start();// 开启线程

    new Thread(l2).start();// 开启线程

  }

}

结果:可能会死锁

  例如:

if LockA

else LockB

2、线程间通讯

线程间通信:就是不同的线程共享同一资源,然后对资源进行不同的操作行为,说白了,在执行的线程运行代码是不一样的,但是代码中还含有共享资源。

例子:

/*共享的资源*/

public class Res {

  private String name;

  private String sex;

 

  public String getName() {

    return name;

  }

 

  public void setName(String name) {

    this.name = name;

  }

 

  public StringgetSex() {

    return sex;

  }

 

  public void setSex(String sex) {

    this.sex = sex;

  }

 

}

/*输入类*/

public class Input implements Runnable {

  private Res r = null;// 定义了一个资源

  public Input(Res r) {// 通过构造方法初始化

    this.r = r;

  }

 

  public void run() {

    int x = 0;

    while (true) {

      if (x == 0) {

         this.r.setName("张三");

         this.r.setSex("");

      } else {

         this.r.setName("Joney");

         this.r.setSex("female");

      } 

      x = (x + 1) % 2;

    }

 

  }

}

/*输出类*/

public class Output implements Runnable {

  private Res re = null;

 

  public Output(Res r) {//初始化资源

    this.re = r;

  }

 

  public void run() {

    while (true) {  

         System.out.println(this.re.getName() + ":" + this.re.getSex());

     

    }

  }

 

}

 

/*测试类*/

public class Text {

  public static void main(String[] agrs) {

    Res r = new Res();

    Input in = new Input(r);

    Output out = new Output(r);

    new Thread(in).start();

    new Thread(out).start();

 

  }

}

从结果中可以看出,结果和我们预测的结果不一样,会出现这样的结果:

Joney:男

张三:female

Joney:female

张三:男

张三:female

3、优化通讯

优化,刚才的通信,就是加上同步锁,在加锁之前,一定要明确,必须是两个或者是多个线程,锁的对象必须是同一个锁

 /*输入类*/

public class Input implements Runnable {

  private Res r = null;// 定义了一个资源

 

  public Input(Res r) {// 通过构造方法初始化

    this.r = r;

  }

 

  public void run() {

    int x = 0;

    while (true) {

      synchronized (r) {//加锁,对象指定的是共享资源

         if (x == 0) {

           this.r.setName("张三");

           this.r.setSex("");

         } else {

           this.r.setName("Joney");

           this.r.setSex("female");

         }

      }

      x = (x + 1) % 2;

    }

  }

}

/*输出类*/

public class Output implements Runnable {

  private Res re = null;

  public Output(Res r) {//初始化资源

    this.re = r;

  }

  public void run() {

    while (true) {

      synchronized (re) {//加锁,对象指定的是共享资源

         System.out.println(this.re.getName() + ":" + this.re.getSex());

      }

    }

  } 

}

4、等待唤醒机制

 利用wait(),notify()和notifyAll()三个方法。

     wait()方法是线程放弃的执行资格,notify()唤醒监视器上等待的线程,默认的是从第一个开始。notifyAll()唤醒的是监视器(锁)上所有等待的线程。为什么这三个函数都是在Object类中,因为监视器(锁)对象是任何对象,要用对象来是线程等待和唤醒,那么就得放在Object类中,才能调用任何对象的方法。

     在共享资源资源上,定义了一个可以标识资源状态 的标识位,在监视器判断标志位,若不符合执行条件则是线程等待,用此时监视器对象来使线程等待,否则继续执行,到最后改变标志位,然后唤醒的等待的线程(是另外一个共享资源的线程),同样另外一个线程(或者是多个)会执行同样的操作。

只有同一个锁上的被等待的线程,可以被同一个锁上的notify()唤醒,不能对不同锁上的线程进行唤醒,就是等待和唤醒必须是同一个锁。

/*共享的资源*/

public class Res {

  private String name;

  private String sex;

  private boolean flag = false;//标志位,用来表示资源的状态

 

  public boolean isFlag() {

    return flag;

  }

 

  public void setFlag(boolean flag) {

    this.flag = flag;

  }

 

  public String getName() {

    return name;

  }

 

  public void setName(String name) {

    this.name = name;

  }

 

  public String getSex() {

    return sex;

  }

 

  public void setSex(String sex) {

    this.sex = sex;

  }

 

}

/*输入类*/

public class Input implements Runnable {

  private Res r = null;// 定义了一个资源

 

  public Input(Res r) {// 通过构造方法初始化

    this.r = r;

  }

 

  public void run() {

    int x = 0;

    while (true) {

      synchronized (r) {// 加锁,对象指定的是共享资源

         if (r.isFlag())// flag=true表示此时里面有资源,或者是资源没有被读取呢,不能继续添加

           try {

             r.wait();

           } catch (InterruptedException e) {

             e.printStackTrace();

           }

         if (x == 0) {

           this.r.setName("张三");

           this.r.setSex("");

         } else {

           this.r.setName("Joney");

           this.r.setSex("female");

         }

         x = (x + 1) % 2;

         r.setFlag(true);// 标识此时已经赋值了,不能在连续赋值了

         r.notify();

      }

 

    }

 

  }

}

/*输出类*/

public class Output implements Runnable {

  private Res r = null;

 

  public Output(Res r) {// 初始化资源

    this.r = r;

  }

 

  public void run() {

    while (true) {

      synchronized (r) {

         if (!r.isFlag())// flag=false,标识此时没有资源,或者资源已经被读取了

           try {

             r.wait();

           } catch (InterruptedException e) {

             e.printStackTrace();

           }

         System.out.println(this.r.getName() + ":" + this.r.getSex());

         r.setFlag(false);// 读取资源后,然后把标志为false,标识此时已经被读取出来了,不能在读取了

         r.notify();

      }

    }

  }

 

}

/*测试类*/

public class Text {

  public static void main(String[] agrs) {

    Res r = new Res();

    Input in = new Input(r);

    Output out = new Output(r);

    new Thread(in).start();

    new Thread(out).start();

 

  }

}

结果:

张三:男

Joney:female

张三:男

Joney:female

张三:男

Joney:female

张三:男

Joney:female

张三:男

5、代码优化

/*共享的资源*/

public class Res {

  private String name;

  private String sex;

  private boolean flag = false;// 标志位,用来表示资源的状态

/*同步函数赋值对象是 this*/

  public synchronized void set(String name, String sex) {// 使用同步函数

    if (flag)

      try {

         this.wait();

      } catch (InterruptedException e) {

         e.printStackTrace();

      }

    this.name = name;//赋值

    this.sex = sex;

    this.flag = true;//改变标识位

    this.notify();//唤醒等待线程

  }

/*同步函数读取  对象是this*/

  public synchronized void show() {// 同步函数

    if (!flag)

      try {

         this.wait();

      } catch (InterruptedException e) {

         e.printStackTrace();

      }

    System.out.println(this.name + ":" + this.sex);//读取

    this.flag = false;//改变标识位

    this.notify();//唤醒等待线程

  }

}

 

/*输入类*/

public class Input implements Runnable {

  private Res r = null;// 定义了一个资源

 

  public Input(Res r) {// 通过构造方法初始化

    this.r = r;

  }

 

  public void run() {

    int x = 0;

    while (true) {

      if (x == 0) {

         r.set("张三", "");

      } else {

         r.set("Joney", "female");

      }

      x = (x + 1) % 2;

 

    }

 

  }

}

/*输出类*/

public class Output implements Runnable {

  private Res r = null;

 

  public Output(Res r) {// 初始化资源

    this.r = r;

  }

 

  public void run() {

    while (true) {

      r.show();

    }

  }

 

}

/*测试类*/

public class Text {

  public static void main(String[] agrs) {

    Res r = new Res();

    new Thread(new Input(r)).start();

    new Thread(new Output(r)).start();

  }

}

 

 

 

 


0 0