多线程的同步依靠的是对象锁机制,synchronized关键字的背后就是利用了封锁来实现对共享资源的互斥访问。参考自http://www.cnblogs.com/phinecos/archive/2010/03/13/1684877.html
实例说明:1.貌似同步,实际不同步的情况
package com.thread.code.sync; /** * 不能实现线程同步的例子 * @author 魅力_小生 * @version [版本号, 2016年3月4日] */ public class CannotSync { public static void main(String[] args) { CannotSync test = new CannotSync(); //定义5个线程,希望不打断输出:线程1--1..5;线程2--1..5;...线程5--1..5; for (int i = 0; i < 5; i++) { new Thread(test.new MyThread(),"线程"+i).start(); } //结果发现:打印结果并没有按顺序输出 /* * 原因:在普通方法前面加synchronized,锁住的是当前的this对象,也就是每个个new MyThread()对象; * 代码中创建了10个线程,而每个线程都持有this对象的对象锁,这不能实现线程的同步 */ } class MyThread implements Runnable{ @Override //貌似同步,实际不同步(当只有一个线程调用时同步,多线程时不同步) public synchronized void run() { for (int i = 0; i < 10; i++) { System.out.println(Thread.currentThread().getName()+"--"+i); } } } }
打印结果:线程1未执行完,线程3打断,接着线程4又打断3,接着线程2又打断4...
线程1--0 线程1--1 线程1--2 线程1--3 线程1--4 线程1--5 线程3--0 线程4--0 线程2--0 线程2--1 线程2--2 线程2--3 线程2--4 线程2--5 线程0--0 ...
下面看看能实现同步的几种情况:
1.同步锁指向同一个对象(外部定义的对象)
package com.thread.code.sync; /** * 实现线程同步的例子1:同步锁指向同一个对象(外部定义的对象) * @author 魅力_小生 * @version [版本号, 2016年3月4日] */ public class Sync1 { public static void main(String[] args) { Sync1 test = new Sync1(); //定义一个共用obj,用于共享资源的锁指向同一个对象,实现同步 Object obj = new Object(); //定义5个线程,共同竞争同步代码块,先竞争到的先执行完同步块,中间不会被打断 for (int i = 0; i < 5; i++) { new Thread(test.new MyThread(obj),"线程"+i).start(); } } class MyThread implements Runnable{ private Object obj; public MyThread(Object obj){ this.obj = obj; } @Override public void run() { synchronized(obj){ for (int i = 0; i < 10; i++) { System.out.println(Thread.currentThread().getName()+"--"+i); } System.out.println("------------"); } } } }
2.同步锁指向同一个对象(内部定义静态对象)
package com.thread.code.sync; /** * 实现线程同步的例子2:同步锁指向同一个对象(内部定义静态对象) * @author 魅力_小生 * @version [版本号, 2016年3月4日] */ public class Sync2 { public static void main(String[] args) { //定义5个线程,共同竞争同步代码块,先竞争到的先执行完同步块,中间不会被打断 for (int i = 0; i < 5; i++) { new Thread(new MyThread(),"线程"+i).start(); } } static class MyThread implements Runnable{ //定义静态对象,用于共享资源的锁指向同一个对象,实现同步 private static Object obj = new Object(); @Override public void run() { synchronized(obj){ for (int i = 0; i < 10; i++) { System.out.println(Thread.currentThread().getName()+"--"+i); } System.out.println("------------"); } } } }
3.使用静态同步方法,而不是普通同步方法
package com.thread.code.sync; /** * 实现线程同步的例子3:使用静态同步方法,而不是普通同步方法 * @author 魅力_小生 * @version [版本号, 2016年3月4日] */ public class Sync3 { public static void main(String[] args) { //定义5个线程,希望不打断输出:线程1--1..5;线程2--1..5;...线程5--1..5; for (int i = 0; i < 5; i++) { new Thread(new MyThread(),"线程"+i).start(); } } static class MyThread implements Runnable{ @Override public void run() { print(); } /* * 静态同步方法: * 静态方法是所有类实例对象所共享的,因此线程对象在访问此静态方法时是互斥访问的,从而可以实现线程的同步 */ private static synchronized void print() { for (int i = 0; i < 10; i++) { System.out.println(Thread.currentThread().getName()+"--"+i); } System.out.println("------------"); } } }
上面这些同步情况的打印结果:线程竞争到资源后,未被打断
线程0--0 线程0--1 线程0--2 线程0--3 线程0--4 线程0--5 线程0--6 线程0--7 线程0--8 线程0--9 ------------ 线程3--0 线程3--1 线程3--2 线程3--3 线程3--4 线程3--5 线程3--6 线程3--7 线程3--8 线程3--9 ------------ 线程4--0 线程4--1 线程4--2 线程4--3 线程4--4 线程4--5 线程4--6 线程4--7 线程4--8 线程4--9 ------------ 线程2--0 线程2--1 线程2--2 线程2--3 线程2--4 线程2--5 线程2--6 线程2--7 线程2--8 线程2--9 ------------ 线程1--0 线程1--1 线程1--2 线程1--3 线程1--4 线程1--5 线程1--6 线程1--7 线程1--8 线程1--9 ------------