JAVA中多线程应用编程基础

JAVA中多线程应用编程基础

2023年8月2日发(作者:)

JAVA中多线程应⽤编程基础多线程应⽤编程基础概念程序是为了完成某个特定任务,使⽤某种计算机语⾔编写的⼀组指令的有序集合进程是具有⼀定独⽴功能的程序的运⾏过程,是系统进⾏资源分配和任务调度的⼀个独⽴单位线程是进程中的⼀个独⽴执⾏线索,是CPU调度和分配的基本单位,⾃⼰基本上不拥有系统资源进程每个进程都有独⽴的代码和数据空间,进程切换成本较⾼,⼀个进程中可以包含1-n个线程,进程是资源 分配的最⼩单位同⼀个进程中的线程可能会有共享代码,可以共享进程的数据空间,每个线程由独⽴的运⾏栈和程序计 数器,线程切换的开销很⼩,线程是CPU调⽤的最⼩单位启动进程进程和线程⼀样分为5个阶段:创建、就绪、运⾏、阻塞和终⽌cmd /c 启动运⾏名称后会关闭关闭窗⼝启动⽅法1ProcessBuilder builder=new ProcessBuilder("cmd","/c","ipconfig/all");//构建进程的对象Process process=(); //启动进程//获取ipconfig/all命令的执⾏结果BufferedReader reader=new BufferedReader(new InputStreamReader(utStream(),"GBK"));//⽤于获取ipconfig/all进程的执⾏结果String tmp=null;while((tmp=ne())!=null)n(tmp);启动⽅法2String cmdStr="cmd /c ipconfig/all";Process process=time().exec(cmdStr);BufferedReader reader=new BufferedReader(newInputStreamReader(utStream(),"GBK"));//⽤于获取ipconfig/all进程的执⾏结果String tmp=null;while((tmp=ne())!=null)n(tmp);应⽤考试系统中⽣成java代码⽂件并编译运⾏//⽣成⽂件File f=new File(""); //这个类名称也可以通过⽤户输⼊查找到if(()) (); //如果已经存在则删除旧有⽂件PrintWriter out=new PrintWriter(new FileWriter(f));n("public class T1 {");n("public static void main(String[] args)throws Exception {");n("n("Hello java!");");n("}}");();//编译,对应的命令为javac ocess process=time().exec("cmd /c javac ");boolean runnable=true;//utStream()获取获取所执⾏进程的输出信息,注意不是报错信息。如果需要获取报错信息则应该使⽤orStream()。注意javac编译器编译通过实际上是没有响应信息的BufferedReader br=new BufferedReader(newInputStreamReader(orStream()));while(true){ String tmp=ne(); //整⾏读取javac编译的报错信息 if(tmp==null) break; //如果没有报错信息则直接退出循环 n(tmp); runnable=false; //告知系统编译失败}//如果编译通过则调⽤解释器java执⾏f(runnable){ process=time().exec("cmd /c java T1"); br=new BufferedReader(new InputStreamReader(utStream()));//输出执⾏结果 while(true) { String tmp=ne(); if(tmp==null) break; n(tmp); }}进程三⼤特征独⽴性:进程是⼀个能够独⽴运⾏的基本单位,是系统资源分配和调度的独⽴单位动态性:进程的实质就是程序的⼀次执⾏过程,动态的产⽣、动态的消亡并发性:任何进程都可以同其它进程⼀起并发执⾏异步性结构特征:进程由程序、数据和进程控制块三部分构成僵⼫进程和孤⼉进程僵⼫进程就是当⼦进程⽐⽗进程先结束,但是⽗进程没有回收⼦进程,并没有释放⼦进程所占⽤的资 源。⽗进程先退出,⼦进程会给init进程接管,⼦进程退出后init会回收⼦进程所占⽤的相关资源是对系统资源的浪费,测试⼈员有业务发现,需要处理解决孤⼉进程就是当⽗进程退出,⽽多个⼦进程还在运⾏孤⼉进程会被init进程管理,并由init进程对其进⾏状态收集⼯作没有什么危害并⾏与并发并⾏是指多个CPU或者多台机器同时执⾏⼀段处理逻辑,是真正的同时执⾏并发是指通过CPU调度算法,使⽤户看上去似乎是在同时执⾏,实际从CPU操作层⾯上不是真正的同时 执⾏线程线程是⽐进程更⼩的执⾏单位线程:轻量级进程LWP,系统负担⼩,主要是CPU分配线程不能独⽴存在,必须存在于进程中每个线程也都有它产⽣、存在和消亡的过程,也是⼀个动态的概念⼀个线程有它⾃⼰的⼊⼝和出⼝以及⼀个顺序执⾏的代码序列为什么使⽤线程减轻编写交互频繁、涉及⾯多的程序的困难改善应⽤的吞吐量有多个处理器的同时可以并发/并⾏运⾏不同的线程主线程线程是进程中的⼀个实体,⽤来描述进程的执⾏,负责执⾏包括在进程内部地址空间中的代码 创建⼀个进程时,它的第⼀个线程称为主线程,是由系统⾃动⽣成的主线程是产⽣其它⼦线程的线程通常都是最后执⾏完成的,因为还需要它来执⾏各种关闭动作。public class Test1{ public static void main(String[] args)throws Exception{ //当java程序运⾏时,⾸先创建⼀个运⾏main⽅法的线程---主线程 n(tThread().getName());//获取运⾏main⽅法的线程名称//在主线程内容可以启动⼦线程 Thread t=new Thread(){ public void run() { n(tThread().getName()); } }; ();//启动线程t的运⾏ (); //阻塞当前main线程 }}进程中线程之间的关系⼀个进程中的线程之间没有⽗⼦关系之分,都是平级关系,所有线程都是⼀样的,⼀个退出不会影响另 外⼀个。但是在主线程中执⾏完毕可以使⽤(int)强制结束当前进程,exit⽅法会使整个进程 停⽌,那么所有的线程都会⾃动退出进程 vs 线程⼀个线程只能属于⼀个进程,⽽⼀个进程可以包含多个线程,⾄少有⼀个线程(主线程)资源调度和分配给进程,同⼀进程中的所有线程共享该进程的所有资源线程在执⾏过程中,共享数据⼀般都需要进⾏协作同步CPU分给线程,真正在处理机上运⾏的是线程线程是指在进程内部的⼀个执⾏单元,也是进程内的可调度的实体,两者都是动态的概念进程和线程最⼤的区别在于:进程是由操作系统来控制的,⽽线程是由进程来控制线程本⾝的数据通常只有寄存器数据以及当前程序在运⾏时使⽤的堆栈,所以线程的切换⽐进程切换的 成本要⼩的多。多个进程的内部数据和状态是完全独⽴的,⽽同⼀个进程内的多线程共享⼀块内存空间和⼀组系统资 源,有可能互相影响。多线程多线程是指同时存在⼏个执⾏体,按⼏个不同的执⾏线索共同⼯作的情况多线程实现单个进程中的并发计算,JDK1.8开始提供了针对并⾏⽀持各个线程间共享进程空间中的数据,并可以利⽤共享单元实现数据交换、实时通信与必要的同步操 作 多线程的程序可以更好的表述和解决现实世界中的具体问题,是计算机应⽤开发和程序设计的⼀个必然 趋势优点:解决了多部分同时运⾏的问题缺点:线程太多会有效率反⽽降低的问题,⼀般计算密集型应⽤不适合多线程java与多线程Java语⾔内置了对多线程的⽀持,可以很⽅便地开发出具备多线程功能,同时处理多个任务的应⽤。每个Java应⽤程序都有⼀个隐藏的主线程Application main⽅法Applet⼩应⽤程序,主线程指挥浏览器加载并执⾏java⼩程序线程的4种实现⽅法继承Thread类Thread类本质上就是⼀个实现了Runnable接⼝的实例,代表⼀个线程对象public class Thread implements Runnable{ public void run() { if (target != null) { (); } }}//定义线程最简单的⽅法就是继承Thread类,需要覆盖定义run⽅法即可启动线程的唯⼀⽅法就是通过Thread类对象的start()实例⽅法,不能直接调⽤run()⽅法。start⽅法本⾝ 是⼀个native⽅法,⽤于启动⼀个新线程,并指定run()⽅法。public class LeftThread extends Thread{ public void run(){ for(int i=0;i<50;i++){ n("画条龙...."+i);//停⽌运⾏,阻塞300ms try{ (300); } catch(InterruptedException e){ tackTrace(); } } }}//可以在主线程种启动这个线程Thread t1=new LeftThread();();//可以启动线程,可以通过tThread().getName()获取线程名称匿名内部类的定义⽅法 new Thread(){ public void run(){....} }.start();();//没有语法错误,但是会发现输出的线程名称为main,不是其它线程,⽽是当前的main主线程。不是多线程问题: 最⼤的限制实际上就是java的单根继承体系,这种⽅式基本不⽤实现Runnable接⼝@FunctionalInterface //注解⽤于声明当前接⼝是⼀个函数式接⼝,可以使⽤lambda表达式替代匿名内部类的写法public interface Runnable { public abstract void run();}独⽴类实现接⼝public class RightThread implements Runnable{ public void run(){ for(int i=0;i<50;i++){ n("画彩虹...."+i); } }}//main⽅法调⽤Thread t1=new Thread(new RightThread());();匿名内部类Thread t1=new Thread(new Runnable(){ public void run(){ for(int i=0;i<50;i++){ n("画彩虹...."+i); } }});();lambda表达式,要求接⼝必须是函数式接⼝Thread t1=new Thread(()->{ for(int i=0;i<50;i++){ n("画彩虹...."+i); }});();使⽤Callable和Future接⼝创建线程创建Callable接⼝的实现类,并实现call()⽅法使⽤FutureTask类来包装Callable接⼝实现类的对象,并且以FutureTask对象作为Thread对象的target 来创建线程接⼝定义Callable接⼝⽤于定义线程的执⾏逻辑。le【juc】@FunctionalInterface //属于函数式接⼝,所以可以直接使⽤lambda表达式进⾏定义public interface Callable { //<>写法叫做泛型,⽤于定义返回的数据类型 V call() throws Exception; //call⽅法就是线程的具体执⾏逻辑,有返回值}Future接⼝⽤于接收Callable接⼝中call⽅法的执⾏结果,并提供测试Callable执⾏情况 public interface Future { //⽤于获取Callable接⼝中call⽅法的执⾏结果 boolean cancel(boolean mayInterruptIfRunning); boolean isCancelled(); boolean isDone(); V get() throws InterruptedException, ExecutionException; V get(long timeout, TimeUnit unit) throws InterruptedException,ExecutionException, TimeoutException;}FutureTask实现类系统提供了⼀个Future接⼝的实现类FutureTaskpublic class FutureTask implements RunnableFuture { public FutureTask(Callable callable) { if (callable == null) throw new NullPointerException(); le = callable; = NEW; // ensure visibility of callable } public void run() { if (state != NEW ||!eAndSwapObject(this, runnerOffset,null,tThread())) return; try { Callable c = callable; //获取属性上的callable对象 if (c != null && state == NEW) { //判定是否为new状态 V result; boolean ran; try { result = (); //调⽤call⽅法,并获取返回值 ran = true; } catch (Throwable ex) { result = null; ran = false; setException(ex); } if (ran) set(result); } } finally { runner = null; int s = state; if (s >= INTERRUPTING) handlePossibleCancellationInterrupt(s); } }}public interface RunnableFuture extends Runnable, Future {... ...}具体使⽤1、定义Callable接⼝的实现类public class MyCallable implements Callable { int begin=0; int end=0; public MyCallable(int begin, int end){ =begin; =end; } public Integer call() throws Exception{ int res=0; for(int i=begin; i<=end; i++){ res+=i; } n(tThread()+":"+res); return res; }}2、调⽤FutureTask[] arr=new FutureTask[10];for(int i=0;i<10;i++){ int begin=i*100+1; int end=(i+1)*100; arr[i]=new FutureTask<>(new MyCallable(begin,end)); Thread t=new Thread(arr[i]); ();}//获取最终计算结果int res=0;for(int i=0;i<;i++) res+=((Integer)arr[i].get()); //通过FutureTask提供的get⽅法获取Callable实现类中call⽅法的执⾏结果n("1+2+3+...+1000="+res);使⽤线程池创建线程java提供了ExecutorService、Callable和Future实现等⼯具以简化线程池的使⽤,线程池的具体实现实 际上是依赖于ThreadPoolExecutor//计算1+2+...+1000public class Test1{ public static void main(String[] args) throws Exception { //创建⼀个固定⼤⼩的线程池,经常⽤于实现使⽤少量的线程以应对短时间的波峰请求 ExecutorService es=edThreadPool(3);//为了获取线程的执⾏结果所以使⽤Callable接⼝定义线程的执⾏逻辑 Future[] fs=new Future[10]; for(int i=0;i<;i++){ int begin=i*100+1; int end=(i+1)*100; Callable caller=new MyCallable(begin,end);//提交⼯作任务,使⽤线程池执⾏任务并获取对应的Future对象 fs[i]=(caller); }//获取最终计算结果 int res=0; for(int i=0;i<;i++) res+=((Integer)fs[i].get()); //通过FutureTask提供的get⽅法获取Callable实现类中call⽅法的执⾏结果 wn();//关闭线程池 n("1+2+3+...+1000="+res); }}Callable接⼝的实现类public class MyCallable implements Callable { int begin = 0; int end = 0;

public MyCallable(int begin, int end) { = begin; = end;} public Integer call() throws Exception { int res = 0; for (int i = begin; i <= end; i++) { res += i; } n(tThread() + ":" + res); return res; }}

发布者:admin,转转请注明出处:http://www.yc00.com/web/1690958000a472895.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信