精华内容
下载资源
问答
  • 最大值.java

    2019-12-30 17:21:43
    一道简单的java算法题,不是很难,重要的是理解思路! 每次都要写50个字感觉太难了,可能是代码 太幼稚了,以后不发这种简单的了。
  • 比如List参数的size可能为 几十个甚至上百个,但是假如对方dubbo接口比较慢,传入50个以上会超时,那么可以每次传入20个,分批执行。通常很多人会写 for 循环或者 while 循环,非常不优雅,无法复用,而且容易出错。...

    一、背景

    现实业务开发中,通常为了避免超时、对方接口限制等原因需要对支持批量的接口的数据分批调用。

    比如List参数的size可能为 几十个甚至上百个,但是假如对方dubbo接口比较慢,传入50个以上会超时,那么可以每次传入20个,分批执行。

    通常很多人会写 for 循环或者 while 循环,非常不优雅,无法复用,而且容易出错。

    下面结合 Java8 的 Stream ,Function ,Consumer 等特性实现分批调用的工具类封装和自测。

    并给出 CompletableFuture 的异步改进方案。

    二、实现

    工具类:

    package com.chujianyun.common.java8.function;  import com.google.common.base.Preconditions;import com.google.common.collect.Lists;import org.apache.commons.collections4.CollectionUtils; import java.util.*;import java.util.function.Consumer;import java.util.function.Function; /** * 执行工具类 * * @author  Created by YanTao on 2020/08/07 */public class ExecuteUtil {      public static  void partitionRun(List dataList, int size, Consumer<List> consumer) {        if (CollectionUtils.isEmpty(dataList)) {            return;        }        Preconditions.checkArgument(size > 0, "size must not be a minus");        Lists.partition(dataList, size).forEach(consumer);    }     public static List partitionCall2List(List dataList, int size, Function<List<T>, List<V>> function) {         if (CollectionUtils.isEmpty(dataList)) {            return new ArrayList<>(0);        }        Preconditions.checkArgument(size > 0, "size must not be a minus");         return Lists.partition(dataList, size)                .stream()                .map(function)                .filter(Objects::nonNull)                .reduce(new ArrayList<>(),                        (resultList1, resultList2) -> {                            resultList1.addAll(resultList2);                            return resultList1;                        });      }     public static  Map partitionCall2Map(List dataList, int size, Function<List<T>, Map<T, V>> function) {        if (CollectionUtils.isEmpty(dataList)) {            return new HashMap<>(0);        }        Preconditions.checkArgument(size > 0, "size must not be a minus");        return Lists.partition(dataList, size)                .stream()                .map(function)                .filter(Objects::nonNull)                .reduce(new HashMap<>(),                        (resultMap1, resultMap2) -> {                            resultMap1.putAll(resultMap2);                            return resultMap1;                        });      }}

    待调用的服务(模拟)

    package com.chujianyun.common.java8.function; import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map; public class SomeManager {     public void aRun(Long id, Listdata) {     }     public List aListMethod(Long id, Listdata) {        return new ArrayList<>(0);    }     public Map aMapMethod(Long id, Listdata) {        return new HashMap<>(0);    }}

    单元测试:

    package com.chujianyun.common.java8.function; import org.apache.commons.lang3.RandomUtils;import org.jeasy.random.EasyRandom;import org.junit.Assert;import org.junit.Before;import org.junit.Test;import org.junit.runner.RunWith;import org.mockito.Mock;import org.mockito.Mockito;import org.mockito.internal.verification.Times;import org.powermock.api.mockito.PowerMockito;import org.powermock.modules.junit4.PowerMockRunner; import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;import java.util.stream.Collectors;import java.util.stream.Stream; import static org.mockito.ArgumentMatchers.any;import static org.mockito.ArgumentMatchers.anyLong; @RunWith(PowerMockRunner.class)public class ExecuteUtilTest {     private EasyRandom easyRandom = new EasyRandom();     @Mock    private SomeManager someManager;     // 测试数据    private List mockDataList;     private int total = 30;     @Before    public void init() {        // 构造30条数据        mockDataList = easyRandom.objects(String.class, 30).collect(Collectors.toList());     }     @Test    public void test_a_run_partition() {        // mock aRun        PowerMockito.doNothing().when(someManager).aRun(anyLong(), any());         // 每批 10 个        ExecuteUtil.partitionRun(mockDataList, 10, (eachList) -> someManager.aRun(1L, eachList));         //验证执行了 3 次        Mockito.verify(someManager, new Times(3)).aRun(anyLong(), any());    }      @Test    public void test_call_return_list_partition() {        // mock  每次调用返回条数(注意每次调用都是这2个)        int eachReturnSize = 2;        PowerMockito                .doReturn(easyRandom.objects(String.class, eachReturnSize).collect(Collectors.toList()))                .when(someManager)                .aListMethod(anyLong(), any());         // 分批执行        int size = 4;        List resultList = ExecuteUtil.partitionCall2List(mockDataList, size, (eachList) -> someManager.aListMethod(2L, eachList));         //验证执行次数        int invocations = 8;        Mockito.verify(someManager, new Times(invocations)).aListMethod(anyLong(), any());         // 正好几轮        int turns;        if (total % size == 0) {            turns = total / size;        } else {            turns = total / size + 1;        }        Assert.assertEquals(turns * eachReturnSize, resultList.size());    }      @Test    public void test_call_return_map_partition() {        // mock  每次调用返回条数        // 注意:        // 如果仅调用doReturn一次,那么每次返回都是key相同的Map,        // 如果需要不覆盖,则doReturn次数和 invocations 相同)        int eachReturnSize = 3;        PowerMockito                .doReturn(mockMap(eachReturnSize))                .doReturn(mockMap(eachReturnSize))                .when(someManager).aMapMethod(anyLong(), any());         // 每批        int size = 16;        Map resultMap = ExecuteUtil.partitionCall2Map(mockDataList, size, (eachList) -> someManager.aMapMethod(2L, eachList));         //验证执行次数        int invocations = 2;        Mockito.verify(someManager, new Times(invocations)).aMapMethod(anyLong(), any());         // 正好几轮        int turns;        if (total % size == 0) {            turns = total / size;        } else {            turns = total / size + 1;        }        Assert.assertEquals(turns * eachReturnSize, resultMap.size());    }     private MapmockMap(int size) {        Map result = new HashMap<>(size);        for (int i = 0; i < size; i++) { // 极力保证key不重复            result.put(easyRandom.nextObject(String.class) + RandomUtils.nextInt(), easyRandom.nextInt());        }        return result;    }  }

    注意:

    1 判空

    .filter(Objects::nonNull) 

    这里非常重要,避免又一次调用返回 null,而导致空指针异常。

    2 实际使用时可以结合apollo配置, 灵活设置每批执行的数量,如果超时随时调整

    3 用到的类库

    集合工具类:commons-collections4、guava (可以不用)

    这里的list划分子list也可以使用stream的 skip ,limit特性自己去做,集合判空也可以不借助collectionutils.

    构造数据:easy-random

    单元测试框架:Junit4 、 powermockito、mockito

    4 大家可以加一些更强大的功能,如允许设置每次调用的时间间隔、并行或并发调用等。

    三、改进

    以上面的List接口为例,将其改为异步版本:

        public static List partitionCall2ListAsync(List dataList,                                                         int size,                                                         ExecutorService executorService,                                                         Function<List<T>, List<V>> function) {         if (CollectionUtils.isEmpty(dataList)) {            return new ArrayList<>(0);        }        Preconditions.checkArgument(size > 0, "size must not be a minus");         ListList                .stream()                .map(eachList -> {                    if (executorService == null) {                        return CompletableFuture.supplyAsync(() -> function.apply(eachList));                    } else {                        return CompletableFuture.supplyAsync(() -> function.apply(eachList), executorService);                    }                 })                .collect(Collectors.toList());          CompletableFuture allFinished = CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture[0]));        try {            allFinished.get();        } catch (Exception e) {            throw new RuntimeException(e);        }        return completableFutures.stream()                .map(CompletableFuture::join)                .filter(CollectionUtils::isNotEmpty)                .reduce(new ArrayList(), ((list1, list2) -> {                    List resultList = new ArrayList<>();                    if(CollectionUtils.isNotEmpty(list1)){                       resultList.addAll(list1);                       }                     if(CollectionUtils.isNotEmpty(list2)){                         resultList.addAll(list2);                       }                    return resultList;                }));    }

    测试代码:

         // 测试数据    private List mockDataList;     private int total = 300;     private AtomicInteger atomicInteger;     @Before    public void init() {        // 构造total条数据        mockDataList = easyRandom.objects(String.class, total).collect(Collectors.toList());     }   @Test public void test_call_return_list_partition_async() {         ExecutorService executorService = Executors.newFixedThreadPool(10);         atomicInteger = new AtomicInteger(0);        Stopwatch stopwatch = Stopwatch.createStarted();        // 分批执行        int size = 2;        List resultList = ExecuteUtil.partitionCall2ListAsync(mockDataList, size, executorService, (eachList) -> someCall(2L, eachList));         Stopwatch stop = stopwatch.stop();        log.info("执行时间: {} 秒", stop.elapsed(TimeUnit.SECONDS));         Assert.assertEquals(total, resultList.size());        // 正好几轮        int turns;        if (total % size == 0) {            turns = total / size;        } else {            turns = total / size + 1;        }        log.info("共调用了{}次", turns);        Assert.assertEquals(turns, atomicInteger.get());          // 顺序也一致        for(int i =0; i< mockDataList.size();i++){            Assert.assertEquals((Integer) mockDataList.get(i).length(), resultList.get(i));        }    }    /**     * 模拟一次调用     */    private List someCall(Long id, List strList) {         log.info("当前-->{},strList.size:{}", atomicInteger.incrementAndGet(), strList.size());        try {            TimeUnit.SECONDS.sleep(2L);        } catch (InterruptedException e) {            e.printStackTrace();        }        return strList.stream()                .map(String::length)                .collect(Collectors.toList());    }

    通过异步可以尽可能快得拿到执行结果。

    四、总结

    1 要灵活运用Java 8 的 特性简化代码

    2 要注意代码的封装来使代码更加优雅,复用性更强

    3 要利用来构造单元测试的数据框架如 java-faker和easy-random来提高构造数据的效率

    4 要了解性能改进的常见思路:合并请求、并发、并行、缓存等。

    如果你觉得本文对你有帮助,欢迎点赞、评论关注你的支持是我创作的最大动力

    34782fbac10bb148d5ce64df3bb38f6a.png

    展开全文
  • (java)leetcode-50:Pow(x, n)

    2017-07-08 11:21:52
    Pow(x, n) Implement pow(x, n). 解题思路: 一开始的想法就是简单的...然后又有一问题就是n -2^32次方的时候,不能直接用n = -n。所以我用一index来存储n的符号,这样在下一次递归,n = n/2的时候乘以index就

    Pow(x, n)

    Implement pow(x, n).


    解题思路:

    一开始的想法就是简单的一个一个乘...果断TLE了。后面想了以下,应该得用递归的方式,每次都是平方这样来乘,计算复杂度也会降到log2(n)。

    然后又有一个问题就是n取 -2^32次方的时候,不能直接用n = -n。所以我用一个index来存储n的符号,这样在下一次递归,n = n/2的时候乘以index就不会出现溢出了。


    public class Solution {
        public double myPow(double x, int n) {
            int index = 1;
    		if(n == 0)
            	return 1;
    		if(n < 0)
            {
            	index = -1;
            	x = 1/x;
            }
    		if(n%2 == 0)
    			return myPow(x*x,n/2*index);
    		else
    			return x*myPow(x*x,n/2*index);
        }
    }


    展开全文
  • java内存

    2018-06-04 10:19:16
    寄存器:寄存的意思是,暂时存放数据,不中每次从内存中,它就是一临时放数据的空间,寄存器是最贴近CPU的,而且CPU只与寄存器中进行存取2.存储器:存储器在CPU外,一般指硬盘,U盘等可以在切断电源后保存资料的...

    几个名词解释:

    1.寄存器寄存的意思是,暂时存放数据,不中每次从内存中取,它就是一个临时放数据的空间,寄存器是最贴近CPU的,而且CPU只与寄存器中进行存取

    2.存储器存储器在CPU外,一般指硬盘,U盘等可以在切断电源后保存资料的设备,容量一般比较大,缺点是读写速度都很慢,普通的机械硬盘读写速度一般是50MB/S左右。

    3.cpu的读取过程 CPU计算时,预先把要用的数据从硬盘读到内存,然后再把即将要用的数据读到寄存器。最理想的情况就是CPU所有的数据都能从寄存器里读到,这样读写速度就快,如果寄存器里没有要用的数据,就要从内存甚至硬盘里面读,那样读写数据占的时间就比CPU运算的时间还多的多。所以评价一款CPU的性能除了频率,缓存也是很重要的指标。按与CPU远近来分,离得最近的是寄存器,然后缓存,最后内存 ,于是  CPU〈------〉寄存器〈---->缓存<----->内存<硬盘

    (关于缓存:Cpu缓存区域因为速度差异还是较多,使得更高程度更大的数据处理起来会稍慢且有卡顿,电脑又将缓存区域分为更细化的三个级别,总的来说就是为了缓冲内存和cpu之间的运行差异,一级缓存是cpu和内存之间的分配出的空间,为了缓解内存和cpu的运行差异,成为高速缓存区;而二级缓存与一级缓存类似,二级缓存为了调节一级缓存和内存之间的速度,处理速度较一级慢,同理三级缓存是为了处理为了调节二级缓存没有处理到的数据。简单的说,就是将缓存区域层层细分,处理从内存大量涌入cpu的数据,逐级处理,运行速度加快,从而提高系统的处理速度。

     如何设置二级缓存?

    系统处理器读取数据是有顺序的,首先从一级缓存然后二级缓存最后从内存读取。设置缓存开启一可以运行 注册表 编辑器,展开HKEY_LOCAL_MACHINESystemCurrentControlSetControlSession ManagerMemory Management分支,双击右侧窗口中的“SecondLevelDataCace”,然后根据自己电脑的cpu和内存大小在窗口设置大小,然后重启电脑即可完成。二利用电脑优化大师这类的软件,找到类似“系统性能优化”,和“文件系统优化”中关于二级缓存选项,保存重启即可。)




    展开全文
  • java面试宝典2012

    2012-12-16 20:43:41
    55、设计4线程,其中两线程每次对j增加1,另外两线程对j每次减少1。写出程序。 40 56、子线程循环10次,接着主线程循环100,接着又回到子线程循环10次,接着再回到主线程又循环100,如此循环50次,请写出程序...
  • java 面试题 总结

    2009-09-16 08:45:34
    28、设计4线程,其中两线程每次对j增加1,另外两线程对j每次减少1。写出程序。 以下程序使用内部类实现线程,对j增减的时候没有考虑顺序问题。 public class ThreadTest1{ private int j; public static ...
  • JAVA面试宝典2010

    2011-12-20 16:13:24
    55、设计4线程,其中两线程每次对j增加1,另外两线程对j每次减少1。写出程序。 36 56、子线程循环10次,接着主线程循环100,接着又回到子线程循环10次,接着再回到主线程又循环100,如此循环50次,请写出程序...
  • Java面试宝典-经典

    2015-03-28 21:44:36
    55、设计4线程,其中两线程每次对j增加1,另外两线程对j每次减少1。写出程序。 36 56、子线程循环10次,接着主线程循环100,接着又回到子线程循环10次,接着再回到主线程又循环100,如此循环50次,请写出程序...
  • Java 面试宝典

    2013-02-01 10:02:08
    1、一".java"源文件中是否可以包括多类(不是内部类)?有什么限制? ...... 7 2、Java 有没有 goto? .......................................................................................................
  • Java面试宝典2012版

    2012-12-03 21:57:42
    55、设计4线程,其中两线程每次对j增加1,另外两线程对j每次减少1。写出程序。 36 56、子线程循环10次,接着主线程循环100,接着又回到子线程循环10次,接着再回到主线程又循环100,如此循环50次,请写出程序...
  • 最新Java面试宝典pdf版

    热门讨论 2011-08-31 11:29:22
    55、设计4线程,其中两线程每次对j增加1,另外两线程对j每次减少1。写出程序。 36 56、子线程循环10次,接着主线程循环100,接着又回到子线程循环10次,接着再回到主线程又循环100,如此循环50次,请写出程序...
  • Java面试宝典2012新版

    2012-06-26 19:20:00
    55、设计4线程,其中两线程每次对j增加1,另外两线程对j每次减少1。写出程序。 36 56、子线程循环10次,接着主线程循环100,接着又回到子线程循环10次,接着再回到主线程又循环100,如此循环50次,请写出程序...
  • Java面试笔试资料大全

    热门讨论 2011-07-22 14:33:56
    55、设计4线程,其中两线程每次对j增加1,另外两线程对j每次减少1。写出程序。 36 56、子线程循环10次,接着主线程循环100,接着又回到子线程循环10次,接着再回到主线程又循环100,如此循环50次,请写出程序...
  • Java面试宝典2010版

    2011-06-27 09:48:27
    55、设计4线程,其中两线程每次对j增加1,另外两线程对j每次减少1。写出程序。 56、子线程循环10次,接着主线程循环100,接着又回到子线程循环10次,接着再回到主线程又循环100,如此循环50次,请写出程序。 ...
  • JAVA面试题最全集

    2010-03-13 13:09:10
    50.JAVA语言如何进行异常处理,关键字:thorws,throw,try,catch,finally 51.Object类(或者其子类)的finalize()方法在什么情况下被调用? 52.一“.java”原文件中是否可以包括多类(不是内部类)? 53.掌握...
  • 张无忌和赵敏有一共同的存钱罐,存钱罐中初始有1000元,然后张无忌存了10次钱,每次存100元,而赵敏取了10次钱,每次取50元,最终存钱罐还剩1500元 Zhangwuji类 package com.demo.threa...

    java中线程的一些相关概念,第4篇(线程同步、死锁、线程间的通信)

    直接po代码和截图

    源码点这里

    我们根据一个案例来讲解线程同步的知识点!

    案例如下:

    张无忌和赵敏有一个共同的存钱罐,存钱罐中初始有1000元,然后张无忌存了10次钱,每次存100元,而赵敏取了10次钱,每次取50元,最终存钱罐还剩1500元

    Zhangwuji类

    package com.demo.thread2;
    
    public class Zhangwuji implements Runnable{
    	
    	private String name;
    	
    	private MoneyBox moneyBox;
    	
    	public Zhangwuji(String name, MoneyBox moneyBox){
    		this.name = name;
    		this.moneyBox = moneyBox;
    	}
    	@Override
    	public void run() {
    		add();
    	}
    	
    	public void add() {
    		for (int frequency = 1; frequency <= 10; frequency++) {
    			System.out.println("#######我是" + name + ",这是我第" + frequency + "次存钱#######");
    			moneyBox.add(100, name, frequency);
    		}
    	}
    
    }
    

    Zhaomin类

    package com.demo.thread2;
    
    public class Zhaomin implements Runnable {
    
    	private String name;
    
    	private MoneyBox moneyBox;
    
    	public Zhaomin(String name, MoneyBox moneyBox) {
    		this.name = name;
    		this.moneyBox = moneyBox;
    	}
    
    	@Override
    	public void run() {
    		get();
    	}
    
    	public void get() {
    		for (int frequency = 1; frequency <= 10; frequency++) {
    			System.out.println("*******我是" + name + ",这是我第" + frequency + "次取钱*******");
    			moneyBox.get(50, name, frequency);
    		}
    	}
    
    }
    

    MoneyBox类

    package com.demo.thread2;
    
    //存钱罐类
    public class MoneyBox {
    	
    	//存钱罐中的余额
    	private double money;
    	
    	public double getMoney() {
    		return money;
    	}
    
    	// 构造函数 /构造方法/构造器
    	public MoneyBox(double money) {
    		this.money = money;
    	}
    	
    	//这是存钱的方法,暂时先不加synchronized(同步),先不写成同步方法,看下什么效果
    	public void add(double inMoney, String threadName, int number) {
    		 double oldMoney = money;
    		 try {
    			 //拿到旧的金额后,让当前线程睡眠会以使别的线程操作它
    			Thread.sleep(50);
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    		 money = oldMoney + inMoney;
    		 System.out.println("-------" + threadName + "第" + number + "次存了" + inMoney + "元,现在存钱罐中的余额=" + money);
    	}
    	
    	//这是取钱的方法,暂时先不加synchronized(同步),先不写成同步方法,看下什么效果
    		public void get(double outMoney, String threadName, int number) {
    			 double oldMoney = money;
    			 try {
    				 //拿到旧的金额后,让当前线程睡眠会以使别的线程操作它
    				Thread.sleep(40);
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    			 money = oldMoney - outMoney;
    			 System.out.println("$$$$$$$" + threadName + "第" + number + "次取了" + outMoney + "元,现在存钱罐中的余额=" + money);
    		}
    
    		@Override
    		public String toString() {
    			return "---------------我是存钱罐,我现在的余额=" + money + "---------------";
    		}
    		
    		
    	
    
    }
    

    Test类

    package com.demo.thread2;
    
    public class Test {
    
    	//测试线程同步
    	public static void main(String[] args) {
    		//存钱罐初始余额为1000元
    		MoneyBox moneyBox = new MoneyBox(1000);
    		System.out.println("-------存钱罐初始余额=" + moneyBox.getMoney() + "-------");
    		
    		//保证张无忌和赵敏这两个线程操作的是同一个对象
    		//利用构造函数传参,把moneyBox存钱罐对象传入
    		Zhangwuji zhangwuji = new Zhangwuji("张无忌", moneyBox);
    		Zhaomin zhaomin = new Zhaomin("赵敏", moneyBox);
    		
    		Thread t1 = new Thread(zhangwuji, "张无忌少侠");
    		Thread t2 = new Thread(zhaomin, "赵敏郡主");
    		
    		//启动线程
    		t1.start();
    		t2.start();
    		
    		//主线程睡眠4秒,以使其他两个线程先执行完
    		try {
    			Thread.sleep(4000);
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    		
    		//打印存钱罐中最终的余额
    		System.out.println(moneyBox);
    	}
    
    }
    

    运行结果如下:存钱罐中的初始额是1000元,张无忌存了10次钱,每次存100,而赵敏取了10次钱,每次取50,最后存钱罐中应该还剩1500元才对,可下面的运行结果却怎么也不对,可以多运行几次进行测试,每次运行结果都可能不一样,反正存钱罐中余额不等于1500,如果等于1500,那估计是巧合吧

    接下来,看改进版

    Zhangwuji2类

    package com.demo.thread2;
    
    public class Zhangwuji2 implements Runnable{
    	
    	private String name;
    	
    	private MoneyBox2 moneyBox2;
    	
    	public Zhangwuji2(String name, MoneyBox2 moneyBox2){
    		this.name = name;
    		this.moneyBox2 = moneyBox2;
    	}
    	@Override
    	public void run() {
    		add();
    	}
    	
    	public void add() {
    		for (int frequency = 1; frequency <= 10; frequency++) {
    			System.out.println("#######我是" + name + ",这是我第" + frequency + "次存钱#######");
    			moneyBox2.add(100, name, frequency);
    		}
    	}
    
    }
    

    Zhaomin2类

    package com.demo.thread2;
    
    public class Zhaomin2 implements Runnable {
    
    	private String name;
    
    	private MoneyBox2 moneyBox2;
    
    	public Zhaomin2(String name, MoneyBox2 moneyBox2) {
    		this.name = name;
    		this.moneyBox2 = moneyBox2;
    	}
    
    	@Override
    	public void run() {
    		get();
    	}
    
    	public void get() {
    		for (int frequency = 1; frequency <= 10; frequency++) {
    			System.out.println("*******我是" + name + ",这是我第" + frequency + "次取钱*******");
    			moneyBox2.get(50, name, frequency);
    		}
    	}
    
    }
    

    MoneyBox2类

    package com.demo.thread2;
    
    //存钱罐类
    public class MoneyBox2 {
    	
    	//存钱罐中的余额
    	private double money;
    	
    	public double getMoney() {
    		return money;
    	}
    
    	// 构造函数 /构造方法/构造器
    	public MoneyBox2(double money) {
    		this.money = money;
    	}
    
    	/**
    	 * 线程同步是为了保证当多个线程同时并发访问某资源时,在任何指定时间只有一个线程
    	 * 可以访问该资源,从而使该资源的数据保持一致
    	 * 其中同步又分为同步方法和同步块。我们先看同步方法,同步方法的实现很简单,只要
    	 * 在方法的声明前面加上 synchronized 关键字就可以。它的原理是在任何时刻一个对象中只
    	          有一个同步方法可以执行。只有对象当前执行的同步方法结束后,同一个对象的另一个同步
    	          方法才可能开始。这里的思想是,保证每个线程在调用对象同步方法时以独占的方法操作该
    	          对象。
    	          线程同步的粒度越小越好,即线程同步的代码块越小越好。这时我们可以使用同步块。
    	          因为同步块后面需要传递同步的对象参数,所以它可以指定更多的对象享受同步的优势,而
    	         不像同步方法那样只有包含相关代码的对象受益。	
    	 */
    	
    	/**
    	 * 同一时刻只能由一个同步方法执行,因为
    	 * 该同步方法已经设置了锁,阻止了其他同步方法的启动
    	 */
    	
    	/**
    	 *
    	 *synchronized(对象)同步块后面的小括号中,可以放任何对象,只要是引用类型(即对象类型)就可以,
    	 *所以synchronized同步块比较灵活,没有局限性(同步块后面需要传递同
    	 *步的对象,所以同步块的好处就是,可以指定更多的对象享受同步的优势),而不像同步方法那样只
    	 *有包含相关代码的对象受益(即,同步方法写在哪个类中,哪个类的对象才能有同步的功能,所以同步方法相
    	 *对于同步块来说,有局限性,所以,我个人建议大家使用同步块)
    	 */
    	
    	//这是存钱的方法,加上synchronized(同步),写成同步方法,看下什么效果
    	public synchronized void add(double inMoney, String threadName, int number) {
    		 double oldMoney = money;
    		 try {
    			 //拿到旧的金额后,让当前线程睡眠会以使别的线程操作它
    			Thread.sleep(50);
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    		 money = oldMoney + inMoney;
    		 System.out.println("-------" + threadName + "第" + number + "次存了" + inMoney + "元,现在存钱罐中的余额=" + money);
    	}
    	
    	//这是取钱的方法,加上synchronized(同步),写成同步方法,看下什么效果
    		public synchronized void get(double outMoney, String threadName, int number) {
    			 double oldMoney = money;
    			 try {
    				 //拿到旧的金额后,让当前线程睡眠会以使别的线程操作它
    				Thread.sleep(40);
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    			 money = oldMoney - outMoney;
    			 System.out.println("$$$$$$$" + threadName + "第" + number + "次取了" + outMoney + "元,现在存钱罐中的余额=" + money);
    		}
    
    		@Override
    		public String toString() {
    			return "---------------我是存钱罐,我现在的余额=" + money + "---------------";
    		}
    }
    

    Test2类

    package com.demo.thread2;
    
    public class Test2 {
    
    	//测试线程同步
    	public static void main(String[] args) {
    		//存钱罐初始余额为1000元
    		MoneyBox2 moneyBox2 = new MoneyBox2(1000);
    		System.out.println("-------存钱罐初始余额=" + moneyBox2.getMoney() + "-------");
    		
    		//保证张无忌和赵敏这两个线程操作的是同一个对象
    		//利用构造函数传参,把moneyBox存钱罐对象传入
    		Zhangwuji2 zhangwuji2 = new Zhangwuji2("张无忌", moneyBox2);
    		Zhaomin2 zhaomin2 = new Zhaomin2("赵敏", moneyBox2);
    		
    		Thread t1 = new Thread(zhangwuji2, "张无忌少侠");
    		Thread t2 = new Thread(zhaomin2, "赵敏郡主");
    		
    		//启动线程
    		t1.start();
    		t2.start();
    		
    		//主线程睡眠4秒,以使其他两个线程先执行完
    		try {
    			Thread.sleep(4000);
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    		
    		//打印存钱罐中最终的余额
    		System.out.println(moneyBox2);
    	}
    
    }
    

    运行结果如下:这结果就是正确的

    接下来,我们再改进一下

    Zhangwuji3类

    package com.demo.thread2;
    
    public class Zhangwuji3 implements Runnable{
    	
    	private String name;
    	
    	private MoneyBox3 moneyBox3;
    	
    	public Zhangwuji3(String name, MoneyBox3 moneyBox3){
    		this.name = name;
    		this.moneyBox3 = moneyBox3;
    	}
    	@Override
    	public void run() {
    		add();
    	}
    	
    	public void add() {
    		for (int frequency = 1; frequency <= 10; frequency++) {
    			System.out.println("#######我是" + name + ",这是我第" + frequency + "次存钱#######");
    			moneyBox3.add(100, name, frequency);
    		}
    	}
    
    }
    

    Zhaomin3类

    package com.demo.thread2;
    
    public class Zhaomin3 implements Runnable {
    
    	private String name;
    
    	private MoneyBox3 moneyBox3;
    
    	public Zhaomin3(String name, MoneyBox3 moneyBox3) {
    		this.name = name;
    		this.moneyBox3 = moneyBox3;
    	}
    
    	@Override
    	public void run() {
    		get();
    	}
    
    	public void get() {
    		for (int frequency = 1; frequency <= 10; frequency++) {
    			System.out.println("*******我是" + name + ",这是我第" + frequency + "次取钱*******");
    			moneyBox3.get(50, name, frequency);
    		}
    	}
    
    }
    

    MoneyBox3类

    package com.demo.thread2;
    
    //存钱罐类
    public class MoneyBox3 {
    	
    	//存钱罐中的余额
    	private double money;
    	
    	public double getMoney() {
    		return money;
    	}
    
    	// 构造函数 /构造方法/构造器
    	public MoneyBox3(double money) {
    		this.money = money;
    	}
    	
    	//这是存钱的方法,加上synchronized(同步)关键字,写成同步块,看下什么效果
    	public void add(double inMoney, String threadName, int number) {
    		/**
    		 * 如果,我们add()函数写成synchronized同步方法,而不是写成synchronized同步块的话,
    		 * 假设add()函数中有一段安全验证等等业务代码,而且这段安全验证等等业务代码执行挺长时间,而在执行这段安
    		 * 全验证代码的这段时间内,其他线程又不能操作(本类/本对象)同一个MoneyBox3对象的其他同
    		 * 步方法,要一直等add同步方法执行结束后,其他线程才能操作(本类/本对象)同一个MoneyBox3对
    		 * 象的其他同步方法,显然,效率比较低
    		 * 所以,建议使用synchronized同步块
    		 */
    		//安全验证等业务代码占用时间
    		 try {
    			 //拿到旧的金额后,让当前线程睡眠会以使别的线程操作它
    			Thread.sleep(50);
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    		//使用同步块,可以减小线程同步的粒度,线程同步的粒度越小越好,即线程同步的代码块越小越好
    		 /*
    		  * 同步代码块可以用更细粒度的控制锁,同步方法锁的范围比较大,而同步代码块范围要小点,一般同步的范围越
    		  * 大,性能就越差,一般需要加锁进行同步的时候,肯定是范围越小越好,这样性能更好
    		  */
    		 synchronized(this){
    //			 double oldMoney = money;
    //			 money = oldMoney + inMoney;
    //			 可以将上面两句话,合二为一
    			 money += inMoney;
    			 System.out.println("-------" + threadName + "第" + number + "次存了" + inMoney + "元,现在存钱罐中的余额=" + money);
    		 }
    	}
    	
    	//这是取钱的方法,加上synchronized(同步)关键字,写成同步块,看下什么效果
    		public void get(double outMoney, String threadName, int number) {
    			/**
    			 * 安全验证等业务代码占用时间
    			 * 假设这里有一段安全验证等等业务代码,而且这段安全验证等等业务代码执行挺长时间
    			 * 
    			 */
    			 try {
    				 //拿到旧的金额后,让当前线程睡眠会以使别的线程操作它
    				Thread.sleep(40);
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    			 //使用同步块,可以减小线程同步的粒度,线程同步的粒度越小越好,即线程同步的代码块越小越好
    			 /*
    			  * 同步代码块可以用更细粒度的控制锁,同步方法锁的范围比较大,而同步代码块范围要小点,一般同步的范围越
    			  * 大,性能就越差,一般需要加锁进行同步的时候,肯定是范围越小越好,这样性能更好
    			  */
    			 synchronized(this){
    //				 double oldMoney = money;
    //				 money = oldMoney - outMoney;
    //				可以 将上面两句话,合二为一
    				 money -= outMoney;
    				 System.out.println("$$$$$$$" + threadName + "第" + number + "次取了" + outMoney + "元,现在存钱罐中的余额=" + money);
    			 }
    		}
    
    		@Override
    		public String toString() {
    			return "---------------我是存钱罐,我现在的余额=" + money + "---------------";
    		}
    	/*
    	 * 小结:
    	 * 同步方法直接在方法上加synchronized实现加锁,同步代码块则在方法内部加锁,很明显,同步方法锁的范
    	 * 围比较大,而同步代码块范围要小点,一般同步的范围越大,性能就越差,一般需要加锁进行同步的时候,肯
    	 * 定是范围越小越好,这样性能更好
    	 * 
    	 * 同步代码块可以用更细粒度的控制锁
    	 * 
    	 * 使用同步块,可以减小线程同步的粒度,线程同步的粒度越小越好,即线程同步的代码块越小越好	
    	 */
    		
    	
    
    }
    

    Test3类

    package com.demo.thread2;
    
    public class Test3 {
    
    	//测试线程同步
    	public static void main(String[] args) {
    		//存钱罐初始余额为1000元
    		MoneyBox3 moneyBox3 = new MoneyBox3(1000);
    		System.out.println("-------存钱罐初始余额=" + moneyBox3.getMoney() + "-------");
    		
    		//保证张无忌和赵敏这两个线程操作的是同一个对象
    		//利用构造函数传参,把moneyBox存钱罐对象传入
    		Zhangwuji3 zhangwuji3 = new Zhangwuji3("张无忌", moneyBox3);
    		Zhaomin3 zhaomin3 = new Zhaomin3("赵敏", moneyBox3);
    		
    		Thread t1 = new Thread(zhangwuji3, "张无忌少侠");
    		Thread t2 = new Thread(zhaomin3, "赵敏郡主");
    		
    		//启动线程
    		t1.start();
    		t2.start();
    		
    		//主线程睡眠4秒,以使其他两个线程先执行完
    		try {
    			Thread.sleep(4000);
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    		
    		//打印存钱罐中最终的余额
    		System.out.println(moneyBox3);
    	}
    
    }
    

    运行结果如下:这结果也是正确的

    展开全文
  • java tp_tp90和tp99指标

    2021-03-08 00:28:39
    TP指标: TP50:指在一时间段内(如5分钟),统计该方法每次调用所消耗的时间,并将这些时间按从小到大的顺序进行排序,50%的那个值作为TP50 值;配置此监控指标对应的报警阀值后,需要保证在这时间段内该方法...
  • 55、设计4线程,其中两线程每次对j增加1,另外两线程对j每次减少1。写出程序。 36 56、子线程循环10次,接着主线程循环100,接着又回到子线程循环10次,接着再回到主线程又循环100,如此循环50次,请写出程序...
  • 银行账户5000块,两夫妻一拿着 存折,一拿着卡,开始钱比赛,每次只能一千块,要求不准出现线程安全问题。 class BankeTread extends Thread { public BankeTread() { } public BankeTread(String ...
  • java 经典习题.doc

    2009-09-16 11:32:59
    题目:古典问题:有一对兔子,从出生后第3月起每月都生一对兔子,小兔子长到第三月后每月又生一对兔子,假如兔子都不死,问每月的兔子总数为多少? 1.程序分析: 兔子的规律为数列1,1,2,3,5,8,13,21.... ...
  • 55、设计4线程,其中两线程每次对j增加1,另外两线程对j每次减少1。写出程序。 36 56、子线程循环10次,接着主线程循环100,接着又回到子线程循环10次,接着再回到主线程又循环100,如此循环50次,请写出程序...
  • 有一1-50的数组,每次随即不重复抽取7数,7次,将这49数写入到文件,剩下那个数显示在屏幕,程序应该怎么写,求大神赐教
  •  Java Bean 是可复用的组件,对Java Bean并没有严格的规范,理论上讲,任何一个Java类都可以是一Bean。但通常情况下,由于Java Bean是被容器所创建(如Tomcat)的,所以Java Bean应具有一无参的构造器,另外,...
  • 55、设计4线程,其中两线程每次对j增加1,另外两线程对j每次减少1。写出程序。 2 56、子线程循环10次,接着主线程循环100,接着又回到子线程循环10次,接着再回到主线程又循环100,如此循环50次,请写出程序...
  • //建立一我的坦克集合类可以出无限坦克 MyTank mt=null; MyTank mt0=null; MyTank mt01=null; MyTank mt02=null; Vector<DiTank> dtk=new Vector();//建立一敌坦克集合类 Props props=null; ...
  • // 分次server端的数据,即每次从流中1024字节,不足1024就一次过来 while(true){ int a = receive_body_byte.length/1024; if(a>=1){ int last=0; Thread.sleep(280); ...
  • paramMap.put("imgFace1", "50,60,100,120"); paramMap.put("hack1", 1); paramMap.put("customerAgreement", 1); String trxString = "10032"; String jsonString = paramMap.toJSONString(); ...
  • 大数--hdu5920 Ugly Problem

    2017-10-15 21:20:13
    构造最多50个回文数,使它们的和是给定的值(1000位) 贪心,每次取前半段数字-1 特例即样例8,10000 //hdu5920 高精度 import java.math.*; import java.util.*; public class Main {  public static ...

空空如也

空空如也

1 2 3
收藏数 48
精华内容 19
关键字:

java每次取50个

java 订阅