今天满世界的微信小程序的新闻,大家都说对于Android原生程序有构成危险了,我也不想了,以后的事谁知道呢, 我还是好好执行一下今年的计划吧。 项目刚刚上线,最近没啥事,我一直感觉自己的Java基础不够扎实,于是就想恶补下一下基础。记得大学英语老师告诉我们,学习要学会炒冷饭,多重复。 我就先从Java多线程的知识再拿出来巩固下,话说无论是从事J2EE还是Android开发,如果对多线程的知识掌握的不好,无论是面试还是工作都说不过去的,至少你不敢说熟悉Java.
我们都知道synchronized关键字可以让线程同步,但是如果用的位置不好,导致运行效率要降低很多。废话不多说,先上代码。
public class Worker { private Random random=new Random(); private ArrayList<Integer> list1=new ArrayList<>(); private ArrayList<Integer> list2=new ArrayList<>(); private synchronized void stageOne(){ try { Thread.sleep(1); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } list1.add(random.nextInt(100)); } private synchronized void stageTwo(){ try { Thread.sleep(1); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } list2.add(random.nextInt(100)); } private void process(){ for(int i=0;i<1000;i++){ stageOne(); stageTwo(); } } public void test(){ long start=System.currentTimeMillis(); Thread t1=new Thread(new Runnable() { @Override public void run() { process(); } }); t1.start(); Thread t2=new Thread(new Runnable() { @Override public void run() { process(); } }); t2.start(); try { t1.join(); t2.join(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } long end = System.currentTimeMillis(); System.out.println("耗时:"+(end-start)); System.out.println("list1 size:"+list1.size()+" list2 size:"+list2.size()); } }
耗时:5057
list1 size:2000 list2 size:2000
把代码改进后,代码如下:
package cave; import java.util.ArrayList; import java.util.Random; public class Worker { private Random random=new Random(); private ArrayList<Integer> list1=new ArrayList<>(); private ArrayList<Integer> list2=new ArrayList<>(); private Object lock1=new Object(); private Object lokck2=new Object(); private void stageOne(){ synchronized (lock1) { try { Thread.sleep(1); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } list1.add(random.nextInt(100)); } } private void stageTwo(){ synchronized (lokck2) { try { Thread.sleep(1); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } list2.add(random.nextInt(100)); } } private void process(){ for(int i=0;i<1000;i++){ stageOne(); stageTwo(); } } public void test(){ long start=System.currentTimeMillis(); Thread t1=new Thread(new Runnable() { @Override public void run() { process(); } }); t1.start(); Thread t2=new Thread(new Runnable() { @Override public void run() { process(); } }); t2.start(); try { t1.join(); t2.join(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } long end = System.currentTimeMillis(); System.out.println("耗时:"+(end-start)); System.out.println("list1 size:"+list1.size()+" list2 size:"+list2.size()); } }
耗时:2536
list1 size:2000 list2 size:2000
从耗时来看,改进后代码时间比之前少了近一半. 我这里stageOne和stageTwo方法代码比较简单,只有一个for循环。如果这个方法里代码有很多,其中一部分是耗时操作,你还把 synchronized关键字来修饰方法,那么耗时将会更多。所以涉及到的线程同步,synchronized所约束的范围越小越好,性能才会越高。这样说可能有点难以理解。我来打个比方吧,如果你去一个店里买衣服,看到一件衣服非常满意,就想去试一下衣服,这个时候正常情况下导购会告诉你试衣间在哪,让你过去试试衣服,你去了试衣间,然后把门关上,这个就相当于加synchronized关键字了。当然了,有的人进去不是去试衣服的,比如2015年的北京三里屯优衣库试衣间那一对男女是在玩耍,我们也管不了,对吧。不过,那个视频看得真是带劲,我还发给一个女生看了。试衣完毕,肯定出来了,其他人会进去锁上门,试衣服。这样进啊出啊进啊出啊,这个试衣间的锁就是相当于synchronized关键字。那么试想有一种情景:你去买衣服,当你要试衣服的时候,你告诉导购要把店面的大门关上(这个时候在外面大门加锁,相当于synchronized),其他人在外面等候,而且店面是上海南京东路步行街的一家店,人流量巨大。如果每个人试衣服都要求导购把店面大门关上,估计你下个月看不到这个店了,因为它关门倒闭了。你换个衣服这样折腾,这生意还能做下去吗?我估计是来了一个大明星,比如汤唯来到南京东路步行街买衣服,那大门估计真的要关上,不然多少男生要流口水啊,这个生意也没法做啊。总之,试衣服只要把试衣间的门锁上就好了,不用关上大门了。
好了,这么一说,你应该理解了为什么synchronized块比synchronized修饰方法性能高了吧,如果还想不通,就想一想你在店外面等着人家试衣服,如果一对男女进去试衣服,你想偷拍都不行啊,这多着急啊,我能理解你的心情!恩,记得只要在试衣间试衣服,坚决不出去。