博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
java多线程系列1:Sychronized关键字
阅读量:5969 次
发布时间:2019-06-19

本文共 6692 字,大约阅读时间需要 22 分钟。

1.Synchronized使用范围:

  • 同步普通方法:锁的是当前对象

    

1 //包含synchronized修饰的同步方法的类addCountClass 2 public class addCountClass { 3  4     private  int count = 0; 5      6     synchronized public void addCount(String user)  7     { 8         try  9         {10             if(user.equals("a")) 11             {12                 count = 100;13                 System.out.println("a set count = 100,over");14                 Thread.sleep(3000);15             }else 16             {17                 count = 200;18                 System.out.println("b set count = 200,over");19             }20             System.out.println(user+" count = "+count);21             22         } catch (Exception e) {23             e.printStackTrace();24         }25         26     }27 }
//线程类Apublic class ThreadA extends Thread {    private addCountClass addcount1;    public ThreadA(addCountClass addcount)     {        super();        this.addcount1 = addcount;    }        public void run()     {        super.run();        addcount1.addCount("a");    }}
//线程类Bpublic class ThreadB extends Thread {    private addCountClass addcount2;    public ThreadB(addCountClass addcount)     {        super();        this.addcount2 = addcount;    }        public void run()     {        super.run();        addcount2.addCount("b");    }    }
//测试类public class MainClass {    public static void main(String[] args) {                addCountClass addCount1 = new addCountClass();        addCountClass addCount2 = new addCountClass();        //线程th1启动后,调用addCount方法时,是用对象addCount1来调用的        Thread th1 = new ThreadA(addCount1);                //线程th2启动后,调用addCount方法时,是用对象addCount2来调用的        Thread th2 = new ThreadB(addCount2);                th1.start();        th2.start();    }}
//输出结果a set count = 100,overb set count = 200,overb count = 200a count = 100/*分析上述结果可知,因为类中Synchronized关键字修饰的是普通方法, *因此锁定的是当前的对象,所以两次调用时分别锁定了addCount1和 *addCount2,所以两个线程都能够正常访问,互不影响*/

 

  • 同步静态方法:锁的是当前class(类)对象

1 //将上一个例子中的addCount方法修改为类中的static方法 2 public class addCountClass { 3  4     private static  int count = 0; 5      6     synchronized public static void addCount(String user)  7     { 8         try  9         {10             if(user.equals("a")) 11             {12                 count = 100;13                 System.out.println("a set count = 100,over");14                 Thread.sleep(3000);15             }else 16             {17                 count = 200;18                 System.out.println("b set count = 200,over");19             }20             System.out.println(user+" count = "+count);21             22         } catch (Exception e) {23             e.printStackTrace();24         }25     }26 }
//运行结果a set count = 100,overa count = 100b set count = 200,overb count = 200/* *此时可以看到,执行结果只可能是一个线程完全执行完addCount方法后 *另一个线程才能够进入该方法,这是因为此时Synchronized修饰的是类 *中的静态方法,因此锁定的当前的class对象,即当前类。因此无论是 *addCount1还是addCount2来调用addCount方法,都会锁定当前类对象*/

 

  • 同步代码块:锁的是()中的对象,synchronized(this)代码块也是锁定当前对象

  当某个需要同步的方法中并不是所有的部分都需要同步时,可将需要同步的代码块用synchronized来修饰,可以提高程序并发效果。

1 //案例1,整个方法都加上了Syncchronized关键字 2 public class Task { 3      4     private int a = 0; 5     synchronized public void longTimeTask()  6     { 7         //模拟一个长时间的无需同步的任务 8         System.out.println("no need Synchronized task start"); 9         try {10             Thread.sleep(3000);11         } catch (InterruptedException e) {12             e.printStackTrace();13         }14         System.out.println("no need Synchronized task end");15         16         //需要同步的任务17         System.out.println("Synchronized task start");18         try {19             Thread.sleep(1000);20         } catch (InterruptedException e) {21             e.printStackTrace();22         }23         System.out.println("Synchronized task end");24     }25 }
View Code
1 //Thread类A 2 public class ThreadA extends Thread { 3     private Task task; 4     public ThreadA(Task task)  5     { 6         super(); 7         this.task = task; 8     } 9     10     public void run() 11     {12         super.run();13         task.longTimeTask();14     }15 }
View Code
1 public class ThreadB extends Thread { 2     private Task task; 3     public ThreadB(Task task)  4     { 5         super(); 6         this.task = task; 7     } 8      9     public void run() 10     {11         super.run();12         task.longTimeTask();13     }14 }
View Code
1 //测试类 2 public class MainClass2 { 3  4     public static void main(String[] args) throws Exception { 5         long startTime = System.currentTimeMillis(); 6          7         Task task = new Task(); 8         Thread th1 = new ThreadA(task); 9         Thread th2 = new ThreadB(task);10         11         th1.start();12         th2.start();13         14         th2.join();15         16         long totalTime = System.currentTimeMillis()-startTime;17         System.out.println("程序总计用时:"+ totalTime);18 19     }20 21 }
//输出结果no need Synchronized task startno need Synchronized task endSynchronized task startSynchronized task endno need Synchronized task startno need Synchronized task endSynchronized task startSynchronized task end程序总计用时:8006毫秒

 分析上述结果可知,两个线程分别去调用加锁方法,第二个需要等到第一个执行完加锁方法中的全部步骤后才可进入执行,即使其中有一部分是无需线程同步的。

修改上述加锁部分,将Synchronized关键字只加到需要同步的代码块上:

1 public class Task { 2      3     private int a = 0; 4      public void longTimeTask()  5     { 6         //模拟一个长时间的无需同步的任务 7         System.out.println("no need Synchronized task start"); 8         try { 9             Thread.sleep(3000);10         } catch (InterruptedException e) {11             e.printStackTrace();12         }13         System.out.println("no need Synchronized task end");14         15         //只在需要同步的任务前加上synchronized16         synchronized(this) 17         {18             System.out.println("Synchronized task start");19             try {20                 Thread.sleep(1000);21             } catch (InterruptedException e) {22                 e.printStackTrace();23             }24             System.out.println("Synchronized task end");25         }26     }27 }

最终程序执行结果为:

//程序运行结果no need Synchronized task startno need Synchronized task startno need Synchronized task endno need Synchronized task endSynchronized task startSynchronized task endSynchronized task startSynchronized task end程序总计用时:5010毫秒

分析上述结果可知,此时线程th1和th2访问longTimeTask方法,但是其中一部分为无需线程同步的,两个线程可以并发执行,而加上了Sychronized方法的代码块。则会在第一个线程进入时加上

task对象锁,第二个线程进入该代码块时不能获取到该锁,所以该代码块无法并行,最终使用代码块加锁的方式,在不影响程序正常执行的情况下,提高了程序并发。

  

  

2.实现原理:JVM 是通过进入、退出对象监视器( Monitor )来实现对方法、同步块的同步的。

具体实现是在编译之后在同步方法调用前加入一个 monitor.enter 指令,在退出方法和异常处插入 monitor.exit 的指令。

其本质就是对一个对象监视器( Monitor )进行获取,而这个获取过程具有排他性从而达到了同一时刻只能一个线程访问的目的。

而对于没有获取到锁的线程将会阻塞到方法入口处,直到获取锁的线程 monitor.exit 之后才能尝试继续获取锁。

 

 

转载于:https://www.cnblogs.com/LearnAndGet/p/9679076.html

你可能感兴趣的文章
jquery 操作iframe、frameset
查看>>
解决vim中不能使用小键盘
查看>>
Eclipse Java @Override 报错
查看>>
linux的日志服务器关于屏蔽一些关键字的方法
查看>>
mysql多实例实例化数据库
查看>>
javascript 操作DOM元素样式
查看>>
HBase 笔记3
查看>>
【Linux】Linux 在线安装yum
查看>>
Atom 编辑器系列视频课程
查看>>
[原][osgearth]osgearthviewer读取earth文件,代码解析(earth文件读取的一帧)
查看>>
使用dotenv管理环境变量
查看>>
Vuex学习
查看>>
bootstrap - navbar
查看>>
服务器迁移小记
查看>>
FastDFS存储服务器部署
查看>>
Android — 创建和修改 Fragment 的方法及相关注意事项
查看>>
swift基础之_swift调用OC/OC调用swift
查看>>
Devexpress 15.1.8 Breaking Changes
查看>>
ElasticSearch Client详解
查看>>
mybatis update返回值的意义
查看>>