对象及变量的并发访问之synchronize同步方法:
1)方法内的变量为线程安全
例子:
public class HasSelfPrivateNum { public void addI(String username){ try{ int num = 0; if(username.equals("a")){ num = 100; System.out.println("a set over"); Thread.sleep(2000); }else{ num = 200; System.out.println("b set over"); } System.out.println(username + " num="+ num); }catch (InterruptedException e){ e.printStackTrace(); } } }
public class ThreadA extends Thread { private HasSelfPrivateNum numRef; public ThreadA(HasSelfPrivateNum numRef) { super(); this.numRef = numRef; } @Override public void run() { super.run(); numRef.addI("a"); } }
public class ThreadB extends Thread { private HasSelfPrivateNum numRef; public ThreadB(HasSelfPrivateNum numRef) { super(); this.numRef = numRef; } @Override public void run() { super.run(); numRef.addI("b"); } }
public class Run { public static void main(String[] args) { HasSelfPrivateNum selfPrivateNum = new HasSelfPrivateNum(); ThreadA threadA = new ThreadA(selfPrivateNum); threadA.start(); ThreadB threadB = new ThreadB(selfPrivateNum); threadB.start(); } }
运行结果:
2)实例变量非线程安全
上面的例子,讲num从私用变量,改成成员变量。再次运行结果:
public class HasSelfPrivateNum { private int num = 0; public void addI(String username){ try{ if(username.equals("a")){ num = 100; System.out.println("a set over"); Thread.sleep(2000); }else{ num = 200; System.out.println("b set over"); } System.out.println(username + " num="+ num); }catch (InterruptedException e){ e.printStackTrace(); } } }
运行结果:
解决非线程安全
public class HasSelfPrivateNum { private int num = 0; synchronized public void addI(String username){ try{ if(username.equals("a")){ num = 100; System.out.println("a set over"); Thread.sleep(2000); }else{ num = 200; System.out.println("b set over"); } System.out.println(username + " num="+ num); }catch (InterruptedException e){ e.printStackTrace(); } } }
再次运行结果:
3)多个对象多个锁
接着上面的实验,改动下,Run类,声明2个对象
public class Run { public static void main(String[] args) { HasSelfPrivateNum selfPrivateNum1 = new HasSelfPrivateNum(); HasSelfPrivateNum selfPrivateNum2 = new HasSelfPrivateNum(); ThreadA threadA = new ThreadA(selfPrivateNum1); threadA.start(); ThreadB threadB = new ThreadB(selfPrivateNum2); threadB.start(); } }
看下效果:
4)synchronize方法与锁对象
实验1
public class MyObject { public void methodA(){ try{ System.out.println("begin methodA threadName=" + Thread.currentThread().getName()); Thread.sleep(5000); System.out.println("end"); }catch (InterruptedException e){ e.printStackTrace(); } } }
public class ThreadA extends Thread{ private MyObject object; public ThreadA(MyObject object) { this.object = object; } @Override public void run() { super.run(); object.methodA(); } }
public class ThreadB extends Thread { private MyObject object; public ThreadB(MyObject object) { this.object = object; } @Override public void run() { super.run(); object.methodA(); } }
public class Run { public static void main(String[] args) { MyObject myObject = new MyObject(); ThreadA thread1 = new ThreadA(myObject); thread1.setName("A"); ThreadB thread2 = new ThreadB(myObject); thread1.start(); thread2.setName("B"); thread2.start(); } }
结果显示:2个线程一同进入了methodA方法。
实验2
改进上面的实验,加个synchronize关键字
synchronized public class MyObject { public void methodA(){ try{ System.out.println("begin methodA threadName=" + Thread.currentThread().getName()); Thread.sleep(5000); System.out.println("end"); }catch (InterruptedException e){ e.printStackTrace(); } } }
结果: 排队进入方法
实验3:
继续改进myObject类,再加一个非同步方法
public class MyObject { synchronized public void methodA(){ try{ System.out.println("begin methodA threadName=" + Thread.currentThread().getName()); Thread.sleep(5000); System.out.println("end"); }catch (InterruptedException e){ e.printStackTrace(); } } public void methodB(){ try { System.out.println("begin methodB threadName=" + Thread.currentThread().getName() + "begin time=" + System.currentTimeMillis()); Thread.sleep(5000); System.out.println("end"); }catch (Exception e){ } } }
同样,让ThreadB调用非同步方法B
public class ThreadB extends Thread { private MyObject object; public ThreadB(MyObject object) { this.object = object; } @Override public void run() { super.run(); object.methodB(); } }
所以,methodB方法也加上synchronize关键字试试:
可以看出来,又同步了奥!