为了让计算机完成某个特定的功能,而编写的一系列的有序指定的集合。即:一段静态的代码。
正在运行的程序。即:动态的过程,有自己的产生、存在和消亡。
一个进程可以划分为若干个小的执行单位,每一个执行单位,就是线程。 
  一个进程可以包含多个线程。 
  若一个程序可以在同一时间执行多个线程,就是支持多线程的。
同一时刻,好像同时执行多个任务(进程)。比如Windows操作系统就是多任务操作系统。多任务可以理解为多进程。
<h2>概念</h2>
同一时刻,好像同时执行多个线程。 
  每个Java程序都有一个隐含的主线程:main方法。
多个线程轮流抢占CPU时间片,因为速度非常快,所以造成了多个线程同时执行的错觉。
⑴ 有效的占用了CPU的资源,从某种意义上来讲提高了效率。 
  ⑵ 提高了用户体验性。
⑴ 程序需要同时执行两个或多个任务。 
  ⑵ 程序需要实现一些等待的任务,比如:用户输入、文件读写操作、网络操作、搜索等。 
  ⑶ 程序需要后台一直完成某项操作。
Java语言使用Thread类及其子类的对象来表示线程。
public Thread() {} 
  构造一个Thread对象。
<h2>Thread(String name)</h2>
  public Thread(String name) {}
  构造一个Thread对象,同时指定线程的名字。
Thread的子类可以通过调用super(String name); 来设置线程的名字。
<h2>Thread(Runnable target, String name)</h2>
  public Thread(Runnable target, String name) {}
  构造一个Thread对象,需要传入一个Runnable的实现类,同时指定该线程的名字。
⑴ 定义一个类,让其继承Thread类,再重写run方法。 
  ⑵ 创建继承Thread的类的对象,并调用对象的start方法。
 class MyThread extends Thread {
   @Override
   public void run() {
     // 任务体
   }
 }
 MyThread mt = new MyThread();
 mt.start();
⑴ 定义一个类,让其实现Runnable接口,再实现run方法。 
⑵ 创建一个Thread对象,将实现Runnable接口的实现类的对象传入Thread的构造方法。 
⑶ 调用Thread对象的start方法。
 class MyRunnable implements Runnable {
   @Override
   public void run() {
     // 任务体
   }
 }
  MyRunnable mr = new MyRunnable();
  Thread t = new Thread(mr);
  t.start();
  <h3>不同点</h3>
   相对于继承Thread类,实现Runnable接口:
    ⑴ 避免了单继承的局限性,更加灵活
    ⑵ 比较适合解决多个线程共享数据资源的情况
    <h4>卖票【多个线程共享数据资源】</h4>
public class Test { 
  public static void main(String[] args) { 
    WindowRunnable wr = new WindowRunnable(); 
    Thread t1 = new Thread(wr, “窗口1”); 
    Thread t2 = new Thread(wr, “窗口2”); 
    Thread t3 = new Thread(wr, “窗口3”); 
    t1.start(); 
    t2.start(); 
    t3.start(); 
  } 
}
class WindowRunnable implements Runnable { 
  private int tickets = 100; // 总票数 
  @Override 
  public void run() { 
    for (;;) { 
      if (0 < tickets) { 
        System.out.println(Thread.currentThread().getName() + “卖出了一张票,剩余票数:” + (–tickets)); 
      } else { 
        System.out.println(Thread.currentThread().getName() + “票卖完了!”); 
        break; 
      } 
    } 
  } 
}
public synchronized void start() {} 
  启动线程,并执行对应的run方法。
public void run() {} 
  子线程要执行的代码,要放入重写(实现)的此方法中。
public static native Thread currentThread(); 
  获取当前正在执行的线程对象。静态方法,通过Thread来调用。
public final void setName(String name) {} 
  设置线程的名称。
public final String getName() {} 
  获取线程的名称。
 <h3>设置和获取线程名称【Thread的子类】</h3>
public class Test { 
  public static void main(String[] args) { 
    MyThread mt1 = new MyThread(); 
    mt1.start(); // Thread-0 【默认线程名字从0开始】 
    MyThread mt2 = new MyThread(“线程2”); 
    mt2.start(); // 线程2 
    MyThread mt3 = new MyThread(); 
    mt3.setName(“线程3”); // 调用设置线程名称的方法 
    mt3.start(); // 线程3 
  } 
}
class MyThread extends Thread { 
  public MyThread() { 
  }
public MyThread(String name) { // 添加有参构造 
    super(name); // 调用父类【Thread】的构造方法 
  }
@Override 
  public void run() { 
    // 因为该线程类继承了Thread,所以可以直接调用【省略了this 完整:this.getName()】 
    System.out.println(getName()); 
  } 
}
 <h3>设置和获取线程名称【Runnable的实现类】</h3>
public class Test { 
  public static void main(String[] args) { 
    MyRunnable mr = new MyRunnable(); 
    Thread t1 = new Thread(mr, “线程1”); // 设置线程名称 
    Thread t2 = new Thread(mr, “线程2”); // 设置线程名称 
    t1.start(); // 线程1 
    t2.start(); // 线程2 
  } 
}
class MyRunnable implements Runnable { 
  @Override 
  public void run() { 
    // 通过调用Thread的静态方法获取当前线程对象,再调用方法获取线程名称 
    System.out.println(Thread.currentThread().getName()); 
  } 
}
public final void setPriority(int newPriority) {} 
  设置线程的优先级。需要传入一个int类型的优先级。优先级范围1-10。注意:不能超过最高优先级【10】或低于最高优先级【1】,否则报错。看源码:
    if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {
        throw new IllegalArgumentException();
    }
  Thread类中有三个常量:
public final static int MIN_PRIORITY = 1; // 最低优先级 
public final static int NORM_PRIORITY = 5; // 默认优先级 
public final static int MAX_PRIORITY = 10; // 最高优先级
注意:<b>优先级高的线程不一定先执行完,它只是具有CPU抢占的优先权。</b>
public final int getPriority() {} 
  返回线程的优先级。
public static native void sleep(long millis) throws InterruptedException; 
  让当前线程休眠(暂停执行)指定的毫秒数。静态方法,通过Thread来调用。
 <h3>设置和获取线程的优先级并测试执行的优先级</h3>
public class Test { 
  public static void main(String[] args) { 
    MyThread mt1 = new MyThread(“最高优先级线程”); 
    mt1.setPriority(Thread.MAX_PRIORITY); // 设置最高优先级【10】 
    mt1.start(); 
    MyThread mt2 = new MyThread(“默认优先级线程”); 
    mt1.setPriority(Thread.NORM_PRIORITY); // 设置默认优先级【5】 
    mt2.start(); 
    MyThread mt3 = new MyThread(“最低优先级线程”); 
    mt3.setPriority(Thread.MIN_PRIORITY); // 设置最低优先级【1】 
    mt3.start(); 
  } 
}
class MyThread extends Thread { 
  public MyThread(String name) { 
    super(name); 
  }
@Override 
  public void run() { 
    for (int i = 0; i < 10; i++) { 
      try { 
        Thread.sleep(300); // 休眠线程300毫秒 
      } catch (InterruptedException e) { 
        e.printStackTrace(); 
      }
  System.out.println(getName() + "被执行了");
}
} 
}
可以看出最终的执行效果具有随机性,所以可以验证: 
   ① 优先级高的线程不一定先执行完,它只是具有CPU抢占的优先权。 
   ② CPU抢占的优先权是随机的。
public final native boolean isAlive(); 
  测试线程是否处于活动状态。
public boolean isInterrupted() {} 
  测试线程是否已经中断。
public void interrupt() {} 
  中断线程,但实际上并没有真正停止线程。方法的本质:给线程添加一个中断的标记。
示例: 
public class Test { 
  public static void main(String[] args) { 
    MyThread mt = new MyThread(); 
    mt.start(); 
    mt.interrupt(); // 添加中断标记 
  } 
}
class MyThread extends Thread { 
  @Override 
  public void run() { 
    try { 
      Thread.sleep(1000); // 线程休眠1000毫秒 
    } catch (InterruptedException e) { 
      // e.printStackTrace(); 
      System.out.println(“我就是被执行的文字!”); 
    } 
  } 
}
示例: 
public class Test { 
  public static void main(String[] args) { 
    MyThread mt = new MyThread(); 
    mt.start();
try {
  Thread.sleep(50); // 主线程休眠(暂停执行)50毫秒
} catch (InterruptedException e) {
  e.printStackTrace();
}
mt.interrupt(); // 添加中断标记
} 
}
class MyThread extends Thread { 
  @Override 
  public void run() { 
    for (;;) { 
      System.out.println(“线程任务打印文字”); 
      if (this.isInterrupted()) { // 判断是否已经添加中断标记 
        break; // 跳出循环 
      } 
    } 
    System.out.println(“============任务结束了============”); 
  } 
}
public static native void yield(); 
  暂停当前正在执行的线程对象,并执行其他线程。静态方法,通过Thread来调用。 
注意:让出CPU的占用权,但是让出的时间具有不确定性。不一定让出CPU占用权的线程最后执行完。
  <h3>查看其中一个线程暂停后的执行结果</h3>
public class Test { 
  public static void main(String[] args) { 
    MyThread1 mt1 = new MyThread1(); 
    mt1.setName(“线程1”); 
    MyThread2 mt2 = new MyThread2(); 
    mt2.setName(“线程2”); 
    MyThread3 mt3 = new MyThread3(); 
    mt3.setName(“线程3”); 
    mt1.start(); 
    mt2.start(); 
    mt3.start(); 
  } 
}
class MyThread1 extends Thread { 
  @Override 
  public void run() { 
    for (int i = 0; i < 20; i++) { 
      if (10 == i) { 
        Thread.yield(); // 暂停当前线程 
        System.out.println(“==========暂停” + getName() + “==========”); 
      }
  System.out.println(getName() + "被执行");
}
System.out.println("==========" + getName() + "执行完毕!==========");
} 
}
class MyThread2 extends Thread { 
  @Override 
  public void run() { 
    for (int i = 0; i < 20; i++) { 
     System.out.println(getName() + “被执行”); 
    } 
  } 
}
class MyThread3 extends Thread { 
  @Override 
  public void run() { 
    for (int i = 0; i < 20; i++) { 
      System.out.println(getName() + “被执行”); 
    } 
  } 
}
public final void join() throws InterruptedException {} 
     让线程抢占CPU的时间片。一旦抢到,该线程肯定会被执行完。 
     应用于当一个线程需要调用另一个线程的执行结果,而另一个线程并未执行完毕,这时就可以调用此方法,以便获取执行的结果。
  <h3>主线程获取另外一子线程的执行结果</h3>
public class Test { 
  public static void main(String[] args) { 
    MyThread mt = new MyThread(); 
    mt.start(); 
    for (int i = 0; i < 10; i++) { 
      System.out.println(mt.sum); // 获取求和的结果 
    }
try {
  System.out.println("让mt线程获取CPU时间片, 请耐心等待结果的输出。。。");
  mt.join(); // 调用join方法,让mt线程获取CPU时间片【若不让mt线程抢占CPU时间片,则主线程打印结果会是0】
} catch (InterruptedException e) {
  e.printStackTrace();
}
System.out.println("1-100的和为:" + mt.sum); // 输出求和的结果
} 
}
class MyThread extends Thread { 
  int sum; // 求和结果 
  @Override 
  public void run() { 
    for (int i = 1; i <= 100; i++) { 
      try { 
        Thread.sleep(15); 
      } catch (InterruptedException e) { 
        e.printStackTrace(); 
      }
  sum += i;
}
} 
}
public final void setDaemon(boolean on) {} 
  将该线程标记为守护线程或用户线程。true为守护线程,false为用户线程。
<h4>区别</h4>
     线程的执行是否要结束的方式
 ⑴ 用户线程有2种方式:
   ① 正常结束(任务执行完毕)
   ② 被中断
     ⑵ 守护线程只有1中方式:
        用户线程执行结束
     注意:如果用户线程已经执行结束,这时不管守护线程有没有结束,其都要结束。
    <h4>JDK中典型的守护线程</h4>
       垃圾回收机制
  <h3>守护线程随着主线程的结束而结束</h3>
public class Test { 
  public static void main(String[] args) { 
    MyThread mt = new MyThread(); 
    mt.setDaemon(true); // 设置为守护线程 
    mt.start();
for (int i = 0; i < 10; i++) {
  try {
    Thread.sleep(10);
  } catch (InterruptedException e) {
    e.printStackTrace();
  }
  System.err.println("主线程执行");
}
System.err.println("==========主线程执行完毕==========");
} 
}
class MyThread extends Thread { 
  @Override 
  public void run() { 
    for (;;) { 
      try { 
        Thread.sleep(40); 
      } catch (InterruptedException e) { 
        e.printStackTrace(); 
      }
  System.out.println("-----守护线程执行任务-----");
}
} 
}
⑴ 调用线程类的stop方法。但该方法已经过时(@Deprecated),不建议使用。 
  ⑵ 调用线程类的interrupt方法。但是不能真正的停止。 
  ⑶ 采用通知的方式。该方式可确保线程以安全的方式结束运行,建议使用。
  <h3>通知方式的实现步骤</h3>
    ⑴ 在线程类中添加一个boolean类型的循环标记,默认为true。
    ⑵ 在线程类中的run方法中,添加一个循环,循环条件为刚才添加的boolean类型的循环标记。
    ⑶ 在线程类中添加一个更新循环标记的方法。
    ⑷ 在需要停止线程时,将循环标记改为false即可。
public class Test { 
  public static void main(String[] args) { 
    MyThread mt = new MyThread(); 
    mt.start();
try {
  Thread.sleep(50); // 主线程休眠(暂停执行)50毫秒
} catch (InterruptedException e) {
  e.printStackTrace();
}
mt.setLoop(false); // 更新循环标记
} 
}
class MyThread extends Thread { 
  private boolean loop = true; // 循环标记
@Override 
  public void run() { 
    while (loop) { // 循环条件为循环标记 
      System.out.println(“线程任务打印文字”); 
    } 
    System.out.println(“============任务结束了============”); 
  }
public void setLoop(boolean loop) { // 更新循环标记的方法 
    this.loop = loop; 
  } 
}
 
新建 —— 就绪 —— 运行 —— 阻塞 —— 死亡
创建线程对象
调用了start方法 
注意:调用此方法的线程将会进入线程队列等待CPU时间片,它只是具备了运行的条件。
抢到了CPU的执行权 
线程的run方法定义了线程的操作和功能。
调用了sleep方法,或wait方法 
在某种特殊的情况下,被人为挂起或输入输出操作时,让出CPU,并临时中止。
线程任务正常执行完毕,或异常停止
多个线程,共同操作同一个数据资源时,有可能其中一个线程还没有执行完毕,而另外一个线程参与进来。这样就会导致数据出现了脏读。这就是线程同步问题。
对多条操作共享数据的语句,只能让一个线程都执行完,其他的线程再参与进来。在其中一个线程执行过程中,其他线程不可以参与执行。
  具体就是:将需要共同操作的代码,上个“锁”。
Java中引入了对象互斥锁的概念,来保证共享数据操作的完整性。 
  每一个对象都对应一个可以称为“互斥锁”的标记。这个标记用来保证在任一时刻,只能有一个线程对象访问该对象。
  <h3>synchronized关键字</h3>
    用synchronized关键字来与对象的互斥锁联系。<b>当某个对象用synchronized修饰时,表明该对象在任一时刻只能有一个线程访问。</b>
 <h3>同步代码块</h3>
    synchronized(对象) { // 对象就是“锁”
      // 需要被同步的代码
    }
 <h3>同步方法</h3>
 修饰符 synchronized 返回值类型 方法名(形参列表) {
   // 需要被同步的代码
 }
  整个方法为同步方法。
注意:
⑴ 需要同步的代码一般里面没有循环。 
     ⑵ 
   ① 普通的同步方法默认的锁对象为:this 
   ② 静态的同步方法默认的锁对象为:当前类.class
⑴ 找到需要同步的代码【多个线程共同操作的代码】。 
  ⑵ 添加同步代码块或同步方法。 
  ⑶ 判断锁对象是否为同一个
⑴ 当前线程的同步代码块、同步方法执行完毕。 
  ⑵ 当前线程在同步代码块、同步方法中遇到break或return终止了该代码块、方法的继续执行。 
  ⑶ 当前线程在同步代码块、同步方法中出现了Error或Exception,导致异常结束。 
  ⑷ 当前线程在同步代码块、同步方法中执行了线程对象的wait 方法。会使当前线程暂停,并释放互斥锁。
当某线程执行同步代码块、同步方法时,程序调用了Thread.sleep()【休眠线程】 或 Thread.yield()【暂停线程,让出CPU的抢占权】,暂停了当前线程的执行。这并不会释放互斥锁。
⑴ 有多个线程。 
  ⑵ 多个线程有共享的数据。 
  ⑶ 多个线程都有操作共享数据的代码。
在一定程度上降低了程序的执行效率。
class WindowRunnable implements Runnable { 
  private int tickets = 100; // 总票数 
  @Override 
  public void run() { 
    for (;;) { 
      if (0 < tickets) { 
          try { 
            Thread.sleep(10); // 让当前线程休眠10毫秒 
          } catch (InterruptedException e) { 
            e.printStackTrace(); 
          }
      System.out.println(Thread.currentThread().getName() + "卖出了一张票,剩余票数:" + (--tickets));
  } else {
      System.out.println(Thread.currentThread().getName() + "票卖完了!");
      break;
  }
}
} 
}
可以看出最终的结果存在负数,所以出现了线程同步问题。
class WindowRunnable implements Runnable { 
  private int tickets = 100; // 总票数 
  private boolean loop = true; // 循环标记
private synchronized void sellTickets() { // 同步方法 
    if (0 < tickets) { 
      try { 
        Thread.sleep(10); // 让当前线程休眠10毫秒 
      } catch (InterruptedException e) { 
        e.printStackTrace(); 
      }
    System.out.println(Thread.currentThread().getName() + "卖出了一张票,剩余票数:" + (--tickets));
  } else {
    System.out.println(Thread.currentThread().getName() + "票卖完了!");
    loop = false;
 }
}
@Override 
  public void run() { 
    while (loop) { 
        sellTickets();
 /* 同步代码块
  synchronized(this) {
    if (0 < tickets) {
        try {
          Thread.sleep(10); // 让当前线程休眠10毫秒
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + "卖出了一张票,剩余票数:" + (--tickets));
    } else {
        System.out.println(Thread.currentThread().getName() + "票卖完了!");
        break;
    }
  }
   */
}
}
}
  <h3>旧的代码【线程同步问题】</h3>
public class Test { 
  public static void main(String[] args) { 
    PrintThread pt1 = new PrintThread(); 
    PrintThread pt2 = new PrintThread(); 
    pt1.start(); 
    pt2.start(); 
  } 
}
class PrintThread extends Thread { 
  @Override 
  public void run() { 
    for (int i = 0; i < 100; i++) { 
      System.out.println(getName() + Singleton.getInstance()); 
    } 
  } 
}
class Singleton { 
  private Singleton(){}
private static Singleton instance;
public static Singleton getInstance() { 
    if (null == instance) { 
      instance = new Singleton(); 
    } 
    return instance; 
  } 
}
可以看到:之前的代码,如果在多个线程中运行,会发现创建出的对象不是唯一的。
  <h3>修改后的单例模式【解决线程同步问题】</h3>
public class Test { 
  public static void main(String[] args) { 
    PrintThread pt1 = new PrintThread(); 
    PrintThread pt2 = new PrintThread(); 
    pt1.start(); 
    pt2.start(); 
  } 
}
class PrintThread extends Thread { 
  @Override 
  public void run() { 
    for (int i = 0; i < 100; i++) { 
      System.out.println(getName() + Singleton.getInstance()); 
    } 
  } 
}
class Singleton { 
  private Singleton(){}
private static Singleton instance;
public static Singleton getInstance() { 
    if (null == instance) { // 提高效率 
      synchronized(Singleton.class) { // 同步代码块 
        if (null == instance) { 
          instance = new Singleton(); 
        } 
      } 
    }
return instance;
} 
}
多个线程之间可以进行通话。
例如:开启了两个线程来打印100以内的数字,结果可能会是: 
      A  1 
      A  2 
      B  3 
      B  4 
      B  5 
      …
 而我们希望是:
      A  1
      B  2
      A  3
      B  4
      ...
  这种交替打印的效果
  这时就需要使用线程的通信
  <h3>notify</h3>
    public final native void notify();
    唤醒某个同步代码块或同步方法中的被wait的一个线程。<b>该方法只能被锁对象【同步代码块或同步方法的互斥锁(唯一性)】执行。</b>
 注意:
⑴ 该方法在Object类中,即每个对象类都有。 
   ⑵ 调用方法的必要条件:当前线程必须具有对该对象的监控权(加锁了)【线程必须可以执行同步方法、或同步代码块中的代码(被锁包起来)】。
  <h3>notifyAll</h3>
    public final native void notifyAll();
    唤醒某个同步代码块或同步方法中的被wait的所有线程。唤醒的顺序是随机的。<b>该方法只能被锁对象【同步代码块或同步方法的互斥锁(唯一性)】执行。</b>
 注意:
⑴ 该方法在Object类中,即每个对象类都有。 
   ⑵ 调用方法的必要条件:当前线程必须具有对该对象的监控权(加锁了)【线程必须可以执行同步方法、或同步代码块中的代码(被锁包起来)】。
  <h3>两个线程交错打印1-100内的数</h3>
public class Test { 
  public static void main(String[] args) { 
    PrintNum pn = new PrintNum(); 
    Thread t1 = new Thread(pn, “打印者一”); 
    Thread t2 = new Thread(pn, “打印者二”); 
    t1.start(); 
    t2.start(); 
  } 
}
class PrintNum implements Runnable { 
  private int num = 0;
@Override 
    public void run() { 
      for (;;) { 
        synchronized (this) { 
          this.notify(); // 在此唤醒上次打印过的线程
        if (num < 100) {
          try {
            Thread.sleep(26);
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
          System.out.println(Thread.currentThread().getName() + "---" + (++num));
          try {
            this.wait(); // 每次打印一个数字,就让当前线程等待
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
        } else {
          break;
    }
    }
 }
} 
}
  <h3>生产者和消费者</h3>
public class Test { 
  public static void main(String[] args) { 
    Storehouse storehouse = new Storehouse(); 
    Producer producer = new Producer(storehouse); 
    Consumer consumer = new Consumer(storehouse); 
    producer.start(); 
    consumer.start(); 
  } 
}
/** 
 * 仓库 
 */ 
class Storehouse { 
  private int total = 0; // 货物总数
/** 
   * 存储方法 
   */ 
  public synchronized void store() { 
    // 唤醒消费者 【可能消费者的线程的抢到的CPU时间片较多,其一旦消费了所有的产品,就会wait,所以需要用生产者来唤醒】 
    this.notify();
if (total < 20) {
  System.out.println("生产者生产了1个产品,当前库存:" + (++total));
} else {
  try {
    this.wait(); // 达到库存上线,停止生产
  } catch (InterruptedException e) {
    e.printStackTrace();
  }
}
}
/** 
   * 取出方法 
   */ 
  public synchronized void getOut() { 
    // 唤醒生产者 【可能生产者的线程的抢到的CPU时间片较多,其一旦生产够了库存,就会wait,所以需要用消费者来唤醒】 
    this.notify();
if (total > 0) {
  System.out.println("消费者消费了1个产品,当前库存:" + (--total));
} else {
  try {
    this.wait(); // 没有库存,无法消费
  } catch (InterruptedException e) {
    e.printStackTrace();
  }
}
} 
}
/** 
 * 生产者 
 */ 
class Producer extends Thread { 
  private Storehouse storehouse;
public Producer(Storehouse storehouse) { 
    this.storehouse = storehouse; 
  }
@Override 
  public void run() { 
    for (;;) { 
      try { 
        Thread.sleep(100); 
      } catch (InterruptedException e) { 
        e.printStackTrace(); 
      } 
      storehouse.store(); 
    } 
  } 
}
/** 
 * 消费者 
 */ 
class Consumer extends Thread { 
  private Storehouse storehouse;
public Consumer(Storehouse storehouse) { 
    this.storehouse = storehouse; 
  }
@Override 
  public void run() { 
    for (;;) { 
      try { 
        Thread.sleep(100); 
      } catch (InterruptedException e) { 
        e.printStackTrace(); 
      } 
      storehouse.getOut(); 
    } 
  } 
}
⑴ 必须在同步的基础上(必须在同步代码块或同步方法中实现通信)。 
 ⑵ 要求调用wait、notify、notifyAll的对象必须为锁对象。
不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就形成了线程的死锁。
public class Test { 
  public static void main(String[] args) { 
    Person p1 = new Person(true); // 小明 
    Person p2 = new Person(false); // 小华 
    p1.start(); 
    p2.start(); 
  } 
}
/** 
 * 小明 
 */ 
class XiaoMing { 
  public void holdOn() { 
    System.out.println(“小明说:你先让我过去,我再让你过去”); 
  }
public void pass() { 
    System.out.println(“小明过了独木桥”); 
  } 
}
/** 
 * 小华 
 */ 
class XiaoHua { 
  public void holdOn() { 
    System.out.println(“小华说:你先让我过去,我再让你过去”); 
  }
public void pass() { 
    System.out.println(“小华过了独木桥”); 
  } 
}
class Person extends Thread { 
  private static final XiaoMing xm = new XiaoMing(); 
  private static final XiaoHua xh = new XiaoHua(); 
  private boolean which; // true代表小明;false代表小华
public Person(boolean which) { // 传入boolean值,创建小明或小华 
    this.which = which; 
  }
@Override 
  public void run() { 
    if (which) { // 小明 
      synchronized (xm) { 
        xm.holdOn(); 
          synchronized(xh) { 
            xm.pass(); 
          } 
        } 
    } else { // 小华 
      synchronized (xh) { 
        xh.holdOn(); 
          synchronized(xm) { 
            xh.pass(); 
          } 
      } 
    } 
  } 
}
原文:http://blog.csdn.net/adsl624153/article/details/70307587