synchronized二三事4
来源:互联网 发布:知乎中央民族大学舞蹈 编辑:程序博客网 时间:2024/06/04 18:53
1、synchronized static
是对当前*.Java中的Class类的锁定,虽然与非静态的有时候执行结果一样,但还是不同的,一个是对Class类持锁,一个是对象持锁。 线程AB是对类持锁,但C是Service对象持锁。AB是同步的,AC是异步的,synchronized static (object){...}也是如此
class Service{synchronized public static void printA(){try{System.out.println(Thread.currentThread().getName()+"在"+System.currentTimeMillis()+" 执行了printA方法");Thread.sleep(3000);System.out.println(Thread.currentThread().getName()+"在"+System.currentTimeMillis()+" 退出了printA方法");}catch(Exception e){e.printStackTrace();}}synchronized public static void printB(){try{System.out.println(Thread.currentThread().getName()+"在"+System.currentTimeMillis()+" 执行了printB方法");System.out.println(Thread.currentThread().getName()+"在"+System.currentTimeMillis()+" 退出了printB方法");}catch(Exception e){e.printStackTrace();}}synchronized public void printC(){System.out.println(Thread.currentThread().getName()+"在"+System.currentTimeMillis()+" 执行了printC方法");System.out.println(Thread.currentThread().getName()+"在"+System.currentTimeMillis()+" 退出了printC方法");}}public class Run extends Thread{private Service s;private int i;public Run(Service s,int i){super();this.s=s;this.i=i;}public void run(){if(i==0) s.printA();else if(i==1) s.printB();else s.printC();}public static void main(String[] args){Service s=new Service();Run r1=new Run(s,0);Run r2=new Run(s,1);Run r3=new Run(s,3);r1.setName("ThreadA");r2.setName("ThreadB");r3.setName("ThreadC");r1.start();r2.start();r3.start();}}
ThreadA在1490239424698 执行了printA方法ThreadC在1490239424698 执行了printC方法ThreadC在1490239424698 退出了printC方法ThreadA在1490239427698 退出了printA方法ThreadB在1490239427698 执行了printB方法ThreadB在1490239427698 退出了printB方法
2.常量池特性
public static void main(String[] args){String a="a";String b="a";System.out.println(a==b);
返回true所以如果同步代码块中的对象是常量的String,而在两个线程中的run方法中都是调用 service.print("AA")虽然属于两个线程,但是是同一个object,即两个线程持有相同的锁,造成线程B不能执行。所以同步代码块的对象都不使用String对象。
3.内部类与同步
(1)代码块synchronized(class2)对class2对象获得锁,其他线程只能以同步的形式访问class2中的静态方法。
class Out{static class In1{public void method1(In2 in2){String name=Thread.currentThread().getName();synchronized(in2){//对In2的实例对象in2持有锁System.out.println(name+"进入到In1中的method1方法");for(int i=0;i<10;i++){System.out.println("i="+i);try {Thread.sleep(100);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}System.out.println(name+"离开In1中的method1方法");}}public synchronized void method2(){String name=Thread.currentThread().getName();System.out.println(name+"进入In1的method2方法中");for(int j=0;j<10;j++){System.out.println("j="+j);try {Thread.sleep(100);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}System.out.println(name+"离开In1中的method2方法");}}static class In2{//In1中的method1中对对象持有锁,所以下面的线程C收到阻塞synchronized public void method1(){String name=Thread.currentThread().getName();System.out.println(name+"进入In2中的method1方法");for(int k=0;k<10;k++){System.out.println("k="+k);try {Thread.sleep(100);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}System.out.println(name+"离开In2中的method1方法");}}}public class Run extends Thread{public static void main(String[] args){final Out.In1 in1=new Out.In1();final Out.In2 in2=new Out.In2();Thread r1=new Thread(new Runnable() {@Overridepublic void run() {// TODO Auto-generated method stubin1.method1(in2);}});Thread r2=new Thread(new Runnable(){public void run(){in1.method2();}});Thread r3=new Thread(new Runnable(){public void run(){in2.method1();}});r1.setName("ThreadA");r2.setName("ThreadB");r3.setName("ThreadC");r1.start();r2.start();r3.start();}}
ThreadA进入到In1中的method1方法ThreadB进入In1的method2方法中j=0i=0j=1i=1i=2j=2j=3i=3i=4j=4j=5i=5i=6j=6i=7j=7j=8i=8j=9i=9ThreadA离开In1中的method1方法ThreadB离开In1中的method2方法ThreadC进入In2中的method1方法k=0k=1k=2k=3k=4k=5k=6k=7k=8k=9ThreadC离开In2中的method1方法
4.锁对象的改变
多个线程访问对象时一定要注意这些对象是否是同一个,如果不是就是各自获得各自对象的锁,以异步方式进行,只有同一个对象时才会以同步方式进行访问。但是要注意改变的是对象,而不是对象的属性,如果同步的对象是user对象,但是在线程中只改变user的name属性值,则两个线程实际上还是同步访问该user对象。
比如下列简化代码
class Task{private String s1="123";public void doLongTimeTask(){try{synchronized(s1){String name=Thread.currentThread().getName();System.out.println(name+" begin "+System.currentTimeMillis());s1="456";//修改了synchronized的对象Thread.sleep(2000);System.out.println(name+" end "+System.currentTimeMillis());}}catch(Exception e){e.printStackTrace();}}}
public static void main(String[] args){Task t=new Task();Thread r1=new Thread(new Runnable() {@Overridepublic void run() {// TODO Auto-generated method stubt.doLongTimeTask();}});Thread r2=new Thread(new Runnable(){public void run(){t.doLongTimeTask();}});try {r1.setName("ThreadA");r2.setName("ThreadB");r1.start();Thread.sleep(50);//注意 sleep是使得String=456的,这样B线程的对象就是S1=456不是123,异步执行//若不加sleep那么B和A针对的是同一个对象,b发生阻塞,要等到a执行完才会获得对象锁r2.start();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}
ThreadA begin 1490252117538ThreadB begin 1490252117589ThreadA end 1490252119538ThreadB end 1490252119589
1 0
- synchronized二三事4
- synchronized二三事1
- synchronized二三事2
- synchronized二三事3
- synchronized
- synchronized
- synchronized
- synchronized
- synchronized
- synchronized
- synchronized
- synchronized
- synchronized
- synchronized
- synchronized
- synchronized
- synchronized
- synchronized
- visual studio 学习
- 在微信里点击拉起APP到特定页面---Apple Universal Link的摸索
- 【面试】实现页面跳转的两种方法
- UIView的layoutSubviews和drawRect方法何时调用
- 浏览器关闭后,Session会话结束了么?
- synchronized二三事4
- C++实现简单的内存池
- 继承 接口实现练习(运动员教练类)
- java使用反射生成JDK动态代理
- Web Service基本概念
- JSS 第 4 篇
- HTTP协议—— 简单认识TCP/IP协议
- 用于替换的正则表达式(多个空格或换行各变为一个空格或换行)
- 【面试】页面之间的值传递