多线程中多个线程共享数据,多个线程对于共享的数据继续操做时,若是咱们很好的控制就会发生错误。接下来看一个多个线程同时操做同一个数据的例子。
java
public class ThreadCount { public static void main(String[] args) { Total total = new Total(); // 建立三个线程给total分别+十、+20、+5 Counter counter1 = new Counter(10, total); Counter counter2 = new Counter(20, total); Counter counter3 = new Counter(5, total); counter1.start(); counter2.start(); counter3.start(); } } //Total类 class Total{ private int total; public void setTotal(int total) { this.total = total; } public int getTotal() { return total; } } //计算类 class Counter extends Thread { private int i; private Total total; Counter(int i, Total total) { this.i = i; this.total = total; } @Override public void run() { total.setTotal(total.getTotal() + i); System.out.println("结果为: " + total.getTotal()); } } //咱们期待的运行结果是: 结果为: 10 结果为: 30 结果为: 35 //实际的运行结果: 结果为: 30 结果为: 30 结果为: 35
如今有两种方法来解决这个问题:数组
(1)run方法添加synchronized括起来的同步代码块多线程
public void run() { synchronized (this) { total.setTotal(total.getTotal() + i); System.out.println("结果为: " + total.getTotal()); } }
(2)增长一个synchronized修饰的方法构成同步方法,而后run方法调用此方法并发
public void run() { add(); } public synchronized void add() { total.setTotal(total.getTotal() + i); System.out.println("结果为: " + total.getTotal()); }
synchronized有什么神通:ide
(1)当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程获得执行。另外一个线程必须等待当前线程执行完这个代码块之后才能执行该代码块。this
(2)然而,当一个线程访问object的一个synchronized(this)同步代码块时,另外一个线程仍然能够访问该object中的非synchronized(this)同步代码块。spa
(3)尤为关键的是,当一个线程访问object的一个synchronized(this)同步代码块时,其余线程对object中全部其它synchronized(this)同步代码块的访问将被阻塞。.net
(4)(3)一样适用其它同步代码块。也就是说,当一个线程访问object的一个synchronized(this)同步代码块时,它就得到了这个object的对象锁。结果,其它线程对该object对象全部同步代码部分的访问都被暂时阻塞。线程
(5)以上规则对其它对象锁一样适用.code
根据(2)http://my.oschina.net/u/2361475/blog/543961中为何notifyAll()必须放在synchronized代码块内,这是由于在ReaderResult类中已经持有了Calculator对象的锁,若是这个时候notifyAll()没有放在synchronized代码块内,这个时候会发生Calculator类中的会抢夺ReaderResult类中已经持有了Calculator对象的锁,而锁只有一把,固然就会报错以下:
java.lang.IllegalMonitorStateException at java.lang.Object.notifyAll(Native Method)
使用synchronized和wait/notify/notifyAll同时使用时注意的一点,请看一个例子:
public class NotifyTest { //这里使用了String类型,这个时候flag引用指向的对象是true private String flag = "true"; class NotifyThread extends Thread { public NotifyThread(String name) { super(name); } public void run() { try { sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (flag) { //flag的对象变为false,对象发生改变 flag = "false"; flag.notifyAll(); } } } class WaitThread extends Thread { public WaitThread(String name) { super(name); } public void run() { synchronized (flag) { while (flag.equals("true")) { System.out.println(getName() + " begin waiting!"); long waitTime = System.currentTimeMillis(); try { flag.wait(); } catch (InterruptedException e) { e.printStackTrace(); } waitTime = System.currentTimeMillis() - waitTime; System.out.println("wait time :" + waitTime); } System.out.println(getName() + " end waiting!"); } } } public static void main(String[] args) throws InterruptedException { System.out.println("Main Thread Run!"); NotifyTest test = new NotifyTest(); NotifyThread notifyThread = test.new NotifyThread("notify01"); WaitThread waitThread01 = test.new WaitThread("waiter01"); WaitThread waitThread02 = test.new WaitThread("waiter02"); WaitThread waitThread03 = test.new WaitThread("waiter03"); notifyThread.start(); waitThread01.start(); waitThread02.start(); waitThread03.start(); } } //运行结果 Exception in thread "notify01" java.lang.IllegalMonitorStateException at java.lang.Object.notifyAll(Native Method)
问题主要是flag引用的对象发生了改变,咱们如何选择synchoronize的锁呢,其实只要咱们将flag换为javaBean就行,如今为了方便起见咱们使用String数组private String flag[] = {"true"}这样也能够解决问题。
看一下正常执行的结果:
public class NotifyTest { private String flag[] = {"true"}; class NotifyThread extends Thread { public NotifyThread(String name) { super(name); } public void run() { try { sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (flag) { flag[0] = "false"; flag.notifyAll(); } } } class WaitThread extends Thread { public WaitThread(String name) { super(name); } public void run() { synchronized (flag) { while (flag[0].equals("true")) { System.out.println(getName() + " begin waiting!"); long waitTime = System.currentTimeMillis(); try { flag.wait(); } catch (InterruptedException e) { e.printStackTrace(); } waitTime = System.currentTimeMillis() - waitTime; System.out.println("wait time :" + waitTime); } System.out.println(getName() + " end waiting!"); } } } public static void main(String[] args) throws InterruptedException { System.out.println("Main Thread Run!"); NotifyTest test = new NotifyTest(); NotifyThread notifyThread = test.new NotifyThread("notify01"); WaitThread waitThread01 = test.new WaitThread("waiter01"); WaitThread waitThread02 = test.new WaitThread("waiter02"); WaitThread waitThread03 = test.new WaitThread("waiter03"); notifyThread.start(); waitThread01.start(); waitThread02.start(); waitThread03.start(); } } //执行结果 Main Thread Run! waiter01 begin waiting! waiter02 begin waiting! waiter03 begin waiting! wait time :1999 waiter03 end waiting! wait time :2000 waiter02 end waiting! wait time :2000 waiter01 end waiting!
java中那个对象是才是锁你们能够转向下面的链接:
http://blog.csdn.net/fyxxq/article/details/8496811