java——并发编程的更多解决方案

1.传统的多线程解决方案:Threads

1,Thread类
2,Runnable接口
jdk1.0

主要缺点:容易滥用;性能不好;线程缺乏统一管理,相互竞争,倒是死机和oom(内存溢出);不能定时操作,定时执行;

oom内存溢出是超出了jvm的内存空间现象。
增加jvm 的内存空间。(OS)
程序申请内存过大,虚拟机无法满足我们,然后自杀了。这个现象通常出现在大图片的APP开发,或者需要用到很多图片的时候。通俗来讲就是我们的APP需要申请一块内存来存放图片的时候,系统认为我们的程序需要的内存过大,及时系统有充分的内存,比如1G,但是系统也不会分配给我们的APP,故而抛出OOM异常,程序没有捕捉异常,故而弹窗崩溃了。

发生OOM的四种情况:

  1. java堆溢出:heap
    Java堆的JVM参数:
    -Xms:初始堆大小,默认值为物理内存的1/64(<1GB),默认(MinHeapFreeRatio参数可以调整)空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制.
    -Xmx:最大堆大小,默认值为物理内存的1/4(<1GB),默认(MaxHeapFreeRatio参数可以调整)空余堆内存大于70%时,JVM会减少堆直到 -Xms的最小限制
    -Xmn:年轻代大小(1.4or lator),此处的大小是(eden + 2 survivor space),与jmap -heap中显示的New gen是不同的。

  2. 栈溢出:stack
    JVM配置参数:
    -Xss: 每个线程的堆栈大小,JDK5.0以后每个线程堆栈大小为1M,以前每个线程堆栈大小为256K.
    在相同物理内存下,减小这个值能生成更多的线程.但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000左右。

  3. 运行时常量溢出:constant
    JVM参数有:
    -XX:PermSize:设置持久代(perm gen)初始值,默认值为物理内存的1/64
    -XX:MaxPermSize:设置持久代最大值,默认为物理内存的1/4

  4. 方法区溢出:directMemory
    方法区主要存储被虚拟机加载的类信息,如类名、访问修饰符、常量池、字段描述、方法描述等。
    相关的JVM参数同运行时常量。

2.线程池

jdk:1.5
在这里插入图片描述
使用线程池可以有策略地管理线程

System.out.println(Runtime.getRuntime().availableProcessors());
//确定你的电脑多并发时,开几个任务最快,是处理器核数的两倍,也即是逻辑处理器数量;

在这里插入图片描述

newFixedThreadPool定长线程池:

可以指定并发量;


public class Test001 {
    public static void main(String[] args) {
        Thread1 t0=new Thread1();
        Thread1 t1=new Thread1();
        Thread1 t2=new Thread1();
        Thread1 t3=new Thread1();
        Thread1 t4=new Thread1();
        Thread1 t5=new Thread1();
        Thread1 t6=new Thread1();
        Thread1 t7=new Thread1();
        Thread1 t8=new Thread1();
        ExecutorService executorService=Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); //可设置并发量,此时设定位最佳数;
        executorService.execute(t0);
        executorService.execute(t1);
        executorService.execute(t2);
        executorService.execute(t3);
        executorService.execute(t4);
        executorService.execute(t5);
        executorService.execute(t6);
        executorService.execute(t7);
        executorService.shutdown();
    }
}
class Thread1 extends Thread{
    @Override
    public void run() {
        for (int i=0;i<100;i++){
            System.out.println(this.getName()+":"+i);
        }
    }
}

在这里插入图片描述
这种线程池线程之间进行抢时间片竞争,输出情况不定;

newSingleThreadExrcutor单线程化线程池

并发量位1

		。。。
        Thread1 t0=new Thread1();
        Thread1 t1=new Thread1();
        Thread1 t2=new Thread1();
        Thread1 t3=new Thread1();
        Thread1 t4=new Thread1();
        Thread1 t5=new Thread1();
        Thread1 t6=new Thread1();
        Thread1 t7=new Thread1();
        Thread1 t8=new Thread1();
        ExecutorService executorService=Executors.newSingleThreadExecutor();	//没有参数
        executorService.execute(t0);
        executorService.execute(t1);
        executorService.execute(t2);
        executorService.execute(t3);
        executorService.execute(t4);
        executorService.execute(t5);
        executorService.execute(t6);
        executorService.execute(t7);
        executorService.shutdown();

在这里插入图片描述
进程不争不抢挨个顺序执行

newScheduledThreadPool调度线程池

可定时执行,延时执行,可设定并发量;
在这里插入图片描述
返回类型与其他不同

public class Test001 {
    public static void main(String[] args) {
        Thread1 t0=new Thread1();
        Thread1 t1=new Thread1();
        Thread1 t2=new Thread1();
        Thread1 t3=new Thread1();
        Thread1 t4=new Thread1();
        Thread1 t5=new Thread1();
        Thread1 t6=new Thread1();
        Thread1 t7=new Thread1();
        Thread1 t8=new Thread1();
        ScheduledExecutorService executorService=Executors.newScheduledThreadPool(3);

        executorService.schedule(t0,1, TimeUnit.SECONDS);//延时一秒
        executorService.execute(t1);//立即执行
        executorService.scheduleAtFixedRate(t2,3,5,TimeUnit.SECONDS);//延时3秒,并每5秒执行一次,定时执行

    }
}
class Thread1 extends Thread{
    @Override
    public void run() {
        for (int i=0;i<3;i++){
            System.out.println(this.getName()+":"+i);
        }
    }
}

在这里插入图片描述
定时,延时减少线程竞争;

newCachedThreadPool缓冲线程池

在这里插入图片描述

 ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
        for (int i = 0; i < 10; i++) {
            final int index = i;
            try {
                Thread.sleep(index * 100);
            } catch (Exception e) {
                e.printStackTrace();
            }

            cachedThreadPool.execute(new Thread1());
        }
      //==========
      lass Thread1 extends Thread{
    @Override
    public void run() {
            System.out.println(Thread.currentThread().getName()+"gg");
    }
}
        

在这里插入图片描述
一个可根据需要创建新线程的线程池,如果现有线程没有可用的,则创建一个新线程并添加到池中,如果有被使用完但是还没销毁的线程,就复用该线程。

综合练习

    public static void main(String[] args) {
        System.out.println(Runtime.getRuntime().availableProcessors());
        // 重用线程池
        // ExecutorService threadPool = Executors.newCachedThreadPool();
        // 定长多线程池(可指定最大并发执行线程的线程池)
        //ExecutorService threadPool = Executors.newFixedThreadPool(4);
        // 单线程队列池(同时只有一个线程执行,且有序执行)
        // ExecutorService threadPool = Executors.newSingleThreadScheduledExecutor();
        // 并发队列线程池(指定并发数量的有序线程池)
        ExecutorService threadPool = Executors.newScheduledThreadPool(2);
        threadPool.execute(newThread("一"));
        threadPool.execute(newThread("二"));
        threadPool.execute(newThread("三"));
        threadPool.execute(newThread("四"));
        threadPool.execute(newThread("五"));
        threadPool.execute(newThread("六"));
        threadPool.shutdown();
    }
    private static Runnable newThread(String flag) {
        Runnable thread1 = new Runnable() {
            public void run() {
                int i = 0;
                while (true) {
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("我是线程" + flag + ",我还活着呢");
                    i++;
                    if (i >= 5)

                        break;
                }
            }
        };
        return thread1;

    }

异步:线程调用与结果获取

Jdk1.5版本除了,提供了线程池技术,还提供了异步调用获取技术:
Jdk1.0线程模型,不能直接获取子线程的执行结果 !
使用中间一个static变量,作为子线程的结果存储!

以前定义一个线程,只能使用thread或runable,
现在又多了一个Callable{ call()}

使用Callable 接口 &Future 接口 组合,完成一个异步结果获:
(这个组合必须使用线程池)
在这里插入图片描述

    public static void main(String[] args) {
        Callable10 callable10=new Callable10();
        ExecutorService executorService= Executors.newFixedThreadPool(8);
        Future future=executorService.submit(callable10);
        System.out.println("submit...");
        try {
            int val= (int) future.get();
            System.out.println("从线程返回的值:"+val);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        executorService.shutdown();
    }
}
class Callable10 implements Callable{
    @Override
    public Object call() throws Exception {
        return 100;
    }
}

在这里插入图片描述

使用Callable 接口 &FutureTsak 类 组合,完成一个异步结果获:
版本一:需要线程池提交任务,需要FutureTask类包装Callable线程类
在这里插入图片描述

   public static void main(String[] args) {
		Callable10 callable10=new Callable10();
        ExecutorService executorService= Executors.newFixedThreadPool(8);
        //用FutureTask类包装
        FutureTask futureTask=new FutureTask(callable10);
        executorService.submit(futureTask);	//提交任务完成
        System.out.println("submit...");
        try {
            int val= (int) futureTask.get();
            System.out.println("从线程返回的值:"+val);
               } catch (Exception e) {
            e.printStackTrace();
        } 
        executorService.shutdown();
    }
}
class Callable10 implements Callable{
    @Override
    public Object call() throws Exception {
        return 100;
    }
}

在这里插入图片描述

版本二:不需要线程池,需要FutureTask类包装Callable线程类,Thread类包装FutureTask类,启动线程
在这里插入图片描述

   public static void main(String[] args) {
        Callable10 callable10=new Callable10();
        //不需要线程池
        //用FutureTask类包装
        FutureTask futureTask=new FutureTask(callable10);
        //用jdk1.0的Thread类包装
        new Thread(futureTask).start();
        System.out.println("submit...");
        try {
            int val= (int) futureTask.get();
            System.out.println("从线程返回的值:"+val);
        } catch (Exception e) {
            e.printStackTrace();
        } 
 }
 class Callable10 implements Callable{
    @Override
    public Object call() throws Exception {
        return 100;
    }
}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值