死锁问题:
例如有两个线程, 线程1与线程2.
线程1在执行的过程中, 要锁定对象1, 2才能完成整个操作, 首先锁定对象1, 再锁定对象2.
线程2在执行的过程中, 要锁定对象2, 1才能完成整个操作, 首先锁定对象2, 再锁定对象1.
某时刻, 线程1已经拥有对象1的锁, 要是再拥有对象2的锁就能完成整个操作, 可惜了, 你等待着的对象2的锁已经被别人拥有了, 执行不下去了.
此时刻, 线程2已经拥有对象2的锁, 要是再拥有对象1的锁就能完成整个操作, 可惜了, 你等待着的对象1的锁已经被别人拥有了, 执行不下去了.
两个对象都已经锁了, 腰都要求对象放锁, 不可能, 那就都等着吧............
死锁例程:
public class DeadLock implements Runnable{ public int flag ; static Object o1 = new Object(); static Object o2 = new Object(); @Override public void run() { System.out.println("flag: "+flag); if(flag == 1) { synchronized(o1){ try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } synchronized(o2){ System.out.println("1"); } } if(flag == 0){ synchronized(o2){ try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } synchronized(o1){ System.out.println("0"); } } } public static void main(String[] args) { DeadLock de1 = new DeadLock(); DeadLock de2 = new DeadLock(); de1.flag = 1; de2.flag = 0; Thread t1 = new Thread(de1); Thread t2 = new Thread(de2); t1.start(); t2.start(); } }
Demo_1:
public class TT1 implements Runnable { public int b; public synchronized void m1() throws Exception { // 只是方法锁定而已, 别的线程无法执行它 b = 1000; // 其他的线程无法再调用它(方法里面的东西(语句)) Thread.sleep(5000); System.out.println("b = "+b); } public void m2() { System.out.println(b); } @Override public void run() { try { m1(); } catch (Exception e) { e.printStackTrace(); } } public static void main(String[] args) throws Exception{ TT1 tt1 = new TT1(); Thread t = new Thread(tt1); t.start(); Thread.sleep(1000); tt1.m2(); } }
运行结果:
1000
b = 1000
Demo_2:
public class TT2 implements Runnable { public int b = 100; public synchronized void m1() throws Exception { // 互斥, 在某一时刻, 保证只有一个线程进入我们这个方法里面 b = 1000; // 但是, 不保证其他的线程是不是能够进入到另外一个方法里面 Thread.sleep(5000); System.out.println("b = "+b); } public void m2() throws Exception { Thread.sleep(2500); b = 2000; } @Override public void run() { try { m1(); } catch (Exception e) { e.printStackTrace(); } } public static void main(String[] args) throws Exception{ TT2 tt = new TT2(); Thread t = new Thread(tt); t.start(); tt.m2(); } }
运行结果:
b = 2000
在Demo_2中, 如果在 m2() 的方法也加 synchronized. 同时在主方法中的 tt.m2() 后面加一句: System.out.println(tt.b);
则, 运行结果为:
1000
b = 1000 // 这句话执行得比较快.
【注】:当某个对象调用了同步方法时, 该对象上的其它同步方法必须等待该同步方法执行完毕后, 才能被执行.
【注】:其实, 写一个同步的东西是挺困难的. 因为每一个方法要不要同步, 你要考虑得非常清楚.如果一个方法
做了同步, 另外一个方法没有做同步, 那么你要记住一点: 别的线程可以自由得访问那个非同步的方法,
并且可能会对你那个同步的方法产生影响, 所以你要保护好某一个类里面的某一个对象的话, 或者说你
要保护好需要同步的那个对象的话, 你必须对访问这个对象的所有方法仔细考虑, 加不加同步, 加了同
步, 很有可能效率很低, 不加同步, 有可能产生数据不一致的现象.