当前位置: 首页 > news >正文

福州网站备案wordpress婚庆主题公园

福州网站备案,wordpress婚庆主题公园,河北省建设厅网站6,网站网站平台建设方案Java创建线程的方式其实只有一种#x1f468;‍#x1f393;一、继承Thread#x1f468;‍#x1f393;二、实现Runnable接口#x1f468;‍#x1f393;三、实现Callable接口#x1f468;‍#x1f393;四、通过线程池创建#x1f468;‍#x1f393;五、总结一般我… Java创建线程的方式其实只有一种‍一、继承Thread‍二、实现Runnable接口‍三、实现Callable接口‍四、通过线程池创建‍五、总结一般我们会认为创建线程的方式是三到四种其实 本质上这四种没有任何区别都是利用ThreadRunnable来进行实现的多线程其实java自始至终创建多线程的方式都只有一种下面一起看下他们是怎么对Runnable进行改造成多种多样的。‍一、继承Thread 继承Thread下面是常见的写法 public class Test1 extends Thread{Overridepublic void run() {while(true){System.out.println(线程1);}}public static void main(String[] args) {new Test1().start();}}利用这种方式实现的线程就是继承Thread类然后重写run方法我们在run方法内部进行线程逻辑的编写。java的start方法会调用start0方法start0是一个native方法底层会调用run方法进行执行线程所以我们是重写run方法。那run方法是怎么来的呢 上面是run方法在Thread中的实现我们可以看到他被注解Override修饰了说明这个方法是父类的方法我们点击左侧红色向上的箭头就会发现跳到了Runnable接口中如下 这样就很简单明了了所以这样就简单明了了我们在继承Thread重写run方法时其实重写的是Runnable的run方法。这这种已经证明了我们开始说的java是利用ThreadRunnable实现的多线程了。 ‍二、实现Runnable接口 这种方式也是需要依赖Thread才能去创建线程如下所示 public class TestThread {public static void main(String[] args) {new Thread(() - {while(true)System.out.println(Runnable多线程1);}).start();new Thread(() - {while(true)System.out.println(Runnable多线程2);}).start();}}那我们来看下这个实现方式到底是如何进行多线程创建的吧我们还是从run方法开始因为Thread启动线程时调用的是自己的run方法那我们就先看下他自己的run方法实现 可以看到Thread的run方法调用的是target.run方法那target是什么呢ctrl左会发现他就是一个Runnable那这个Runnable怎么来的呢我们创建过程中只在Thread的构造方法中传入了Runnable那是不是在这里咱们一起看下 这里没有做什么实质的操作所以继续看最后调用到了这里 private void init(ThreadGroup g, Runnable target, String name,long stackSize, AccessControlContext acc) {if (name null) {throw new NullPointerException(name cannot be null);}this.name name.toCharArray();Thread parent currentThread();SecurityManager security System.getSecurityManager();if (g null) {/* Determine if its an applet or not *//* If there is a security manager, ask the security managerwhat to do. */if (security ! null) {g security.getThreadGroup();}/* If the security doesnt have a strong opinion of the matteruse the parent thread group. */if (g null) {g parent.getThreadGroup();}}/* checkAccess regardless of whether or not threadgroup isexplicitly passed in. */g.checkAccess();/** Do we have the required permissions?*/if (security ! null) {if (isCCLOverridden(getClass())) {security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);}}g.addUnstarted();this.group g;this.daemon parent.isDaemon();this.priority parent.getPriority();if (security null || isCCLOverridden(parent.getClass()))this.contextClassLoader parent.getContextClassLoader();elsethis.contextClassLoader parent.contextClassLoader;this.inheritedAccessControlContext acc ! null ? acc : AccessController.getContext();this.target target; // 这里是关键点setPriority(priority);if (parent.inheritableThreadLocals ! null)this.inheritableThreadLocals ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);/* Stash the specified stack size in case the VM cares */this.stackSize stackSize;/* Set thread ID */tid nextThreadID();}我们会发现这个方法内部将我们从构造器中传入的Runnable对象放到了this.target中所以可以看到Thread中的run方法调用的就是我们重写的run方法。所以这个也证明了java中是通过ThreadRunnable实现的多线程方式。 ‍三、实现Callable接口 这种方式我们需要依赖FutrureTask其实我们可以接受返回值也得归功FutureTask下面是常见的实现代码 public class TestThread {public static void main(String[] args) throws Exception{FutureTaskString futureTask new FutureTask(()-{int i 0 ;while(i100)System.out.println(Callable线程1在执行i);return 线程1执行完了;});FutureTaskString futureTask2 new FutureTask(()-{int i 0 ;while(i100)System.out.println(Callable线程2在执行i);return 线程2执行完了;});new Thread(futureTask).start();new Thread(futureTask2).start();System.out.println(futureTask.get());System.out.println(futureTask2.get());}}run方法才是多线程的执行地方还是一样我们还是从run方法开始看我们点击下new Thread会进入Thread的构造器发现进入的构造器和第二种是一样的 这就说明FutureTask一定实现了或者继承了Runnable接口其实FutureTask实现了RunnableFuture接口而RunnableFuture继承了Runnable接口因为继承和实现的特性相当于FutureTask实现了Runnable接口。那走到这个构造器就是理所当然那的了。所以与第二种方式相同的是Thread调用的target.run就是FutureTask的run了。我们来看下FutureTask的run方法吧 public void run() {if (state ! NEW ||!UNSAFE.compareAndSwapObject(this, runnerOffset,null, Thread.currentThread()))return;try {CallableV c callable;if (c ! null state NEW) {V result;boolean ran;try {result c.call();ran true;} catch (Throwable ex) {result null;ran false;setException(ex);}if (ran)set(result);}} finally {// runner must be non-null until state is settled to// prevent concurrent calls to run()runner null;// state must be re-read after nulling runner to prevent// leaked interruptsint s state;if (s INTERRUPTING)handlePossibleCancellationInterrupt(s);}}上面是FutureTask的run方法里面真正调用的是c.call方法看到call方法应该就明白了不错这个call就是我们传入到FutureTask中的Callable实例的call方法所以FutureTask的调用路线也就清晰了Thread.start–Thread.run–FutureTask.run–Callable.call。而FutureTask则是Runnable的子类所以也证明了我们一开始说的java是通过ThreadRunnable来实现的多线程。此外通过这里我们还可以清洗的看到FutureTask是怎么实现参数返回接收的就是因为call方法有返回然后FutureTask的run方法接收到返回后将他存放到自身的泛型V中然后我们就可以直接通过FutureTask.get方法进行获取了。其实这种思想java里有很多比如常见的http请求的包装类也是通过这种思想来处理流数据的。 ‍四、通过线程池创建 线程池这里咱们采用自己实现的线程池来进行解释说明其实没啥区别只不过是我们一般使用线程池都是禁止直接使用jdk自带线程池的所以才有用自己实现的线程池来看这个问题 ThreadPoolExecutor threadPoolExecutor new ThreadPoolExecutor(1,1, 60,TimeUnit.SECONDS, new SynchronousQueueRunnable(),Executors.defaultThreadFactory(),new ThreadPoolExecutor.DiscardPolicy() );threadPoolExecutor.execute(()-{while(true){System.out.println(线程4执行中);}});关于各个参数的意思这里就不解释了需要的看这里4万字爆肝总结java多线程知识点言归正传我们看下线程池是怎么创建线程的线程池提交任务有submit和execute还有一个定时的schedule不过schedule他的线程池类不是这个不过原理一样这里只介绍ThreadPoolExecutor的。我们看下execute的实现方法 public void execute(Runnable command) {if (command null)throw new NullPointerException();// 此处省略原文注释int c ctl.get();if (workerCountOf(c) corePoolSize) {//判断线程是否小于核心线程数很明显第一次会进入这里if (addWorker(command, true))return;c ctl.get();}if (isRunning(c) workQueue.offer(command)) {int recheck ctl.get();if (! isRunning(recheck) remove(command))reject(command);else if (workerCountOf(recheck) 0)addWorker(null, false);}else if (!addWorker(command, false))reject(command);}很明显第一次执行会执行addWorker(command, true)这个方法我们再看下这个方法做了什么 private boolean addWorker(Runnable firstTask, boolean core) {retry:for (;;) {int c ctl.get();int rs runStateOf(c);// Check if queue empty only if necessary.if (rs SHUTDOWN ! (rs SHUTDOWN firstTask null ! workQueue.isEmpty()))return false;for (;;) {int wc workerCountOf(c);if (wc CAPACITY ||wc (core ? corePoolSize : maximumPoolSize))return false;if (compareAndIncrementWorkerCount(c))break retry;c ctl.get(); // Re-read ctlif (runStateOf(c) ! rs)continue retry;// else CAS failed due to workerCount change; retry inner loop}}boolean workerStarted false;boolean workerAdded false;Worker w null;try {w new Worker(firstTask);//这个firstTask实际就是我们从execute传入的Runnable实现类final Thread t w.thread;//获取thread因为线程开启必须利用Thread的start方法这两步就是最关键的地方if (t ! null) {final ReentrantLock mainLock this.mainLock;mainLock.lock();try {// Recheck while holding lock.// Back out on ThreadFactory failure or if// shut down before lock acquired.int rs runStateOf(ctl.get());if (rs SHUTDOWN ||(rs SHUTDOWN firstTask null)) {if (t.isAlive()) // precheck that t is startablethrow new IllegalThreadStateException();workers.add(w);int s workers.size();if (s largestPoolSize)largestPoolSize s;workerAdded true;}} finally {mainLock.unlock();}if (workerAdded) {t.start();//这里真正调用了线程启动workerStarted true;}}} finally {if (! workerStarted)addWorkerFailed(w);}return workerStarted;}最关键的两步笔者在代码中加了注释了可以看到会将我们传入的Runnable的实现类交给Worker的构造器那我们看看这个构造器又干了什么 可以看到在这个构造器里面将我们传入的Runnable给到了自己的Runnable对他的私有变量进行了初始化然后又对thread进行了初始化而初始化Thread时传入了this注意传入的是this。因为Worker实现了Runable所以当我们真正执行start方法时调用的应该是Worker的run方法所以我们到这里应该去看run方法了run方法很简单他直接调用了runWorer方法那看下runWorker的实现 final void runWorker(Worker w) {Thread wt Thread.currentThread();Runnable task w.firstTask;//将Runnable的对象指向一个新的引用w.firstTask null;//失效原引用w.unlock(); // allow interrupts//加锁worker实现了AQS支持锁boolean completedAbruptly true;try {while (task ! null || (task getTask()) ! null) {w.lock();// If pool is stopping, ensure thread is interrupted;// if not, ensure thread is not interrupted. This// requires a recheck in second case to deal with// shutdownNow race while clearing interruptif ((runStateAtLeast(ctl.get(), STOP) ||(Thread.interrupted() runStateAtLeast(ctl.get(), STOP))) !wt.isInterrupted())wt.interrupt();try {beforeExecute(wt, task);Throwable thrown null;try {task.run();//这里相当于运行了我们在execute中传入的Runnable对象的run方法了。} catch (RuntimeException x) {thrown x; throw x;} catch (Error x) {thrown x; throw x;} catch (Throwable x) {thrown x; throw new Error(x);} finally {afterExecute(task, thrown);}} finally {task null;w.completedTasks;w.unlock();}}completedAbruptly false;} finally {processWorkerExit(w, completedAbruptly);}}看笔者在代码中加的注释很清晰就看到最终调用的是我们从execute中传入的Runnable的对象的run方法。所以我们看到这里也是可以得出一个解决线程池还是利用ThreadRunnable接口一起实现的多线程。那么来从新梳理下线程池的调用过程 execute(Runnable)– addWorker(command, true)–内部对Worker(Runnale)进行初始化Worker该类实现了Runnable初始化Worker时生产线程Thread传入Worker自己之后获取上一步生产的thread调用start方法。执行start方法实际执行的是Worker的run方法worker.run方法调用了runWorker方法该方法执行时是将Worker的Runnable的对象的run方法进行调用执行。而Worker的Runnable的对象就是在addWorker中由execute方法传入的Runnable实现类。这样整个流程就很清晰了我们也是可以佐证一开始说的观点了。 ‍五、总结 看了以上四种分析我们可以清晰的发现了java中其实创建线程的方式就只有一种就是利用ThreadRunnable来实现多线程。其他多有方式都是对这个实现方式的变种。如有不对欢迎路过的朋友指正也希望能帮到路过的朋友
http://www.w-s-a.com/news/738883/

相关文章:

  • 沈阳做微信和网站的公司网站在线支付接口
  • 重庆整合网络营销百度seo快速提升排名
  • 设计师网站外网百度分析工具
  • 旅游网站建设技术解决方案wordpress主题安装后找不到
  • 网站图片文字排版错误管理系统界面设计
  • 网站建设 台州广州惠科互联网技术有限公司
  • 网站页面尺寸大小四川鸿业建设集团网站
  • 做女朋友的网站局网站建设方案word
  • 做阿里国际网站会有成效吗科技网站有哪些
  • 高端公司网站建设北京两学一做网站
  • 黄埔网站建设设计wordpress 文件夹改名
  • 怎么什么软件可以吧做网站最火的二十个电商app
  • wordpress theme sage网站seo优化加推广
  • 建设一个大型电影网站公司网站建设工作总结
  • 传奇网站一般怎么做的宇泽佛山网站建设
  • google网站入口电商运营十大基础知识
  • 建设公司网站的细节中国建设网网站
  • 重庆美邦建网站宝安网页设计
  • 建网站的地址十堰做网站
  • 怎么评判一个网站做的好与坏专做情侣装网站
  • 网站管理助手v3历史上的今天 网站如何做
  • 网站建设与管理的就业方向网站开发前端模板
  • 对网站建设的维护深圳网络推广推荐
  • wordpress多站共享授权码wordpress数据库缓存插件
  • 建一个购物网站多少钱上海商标注册
  • 琪觅公司网站开发面点培训学校哪里有
  • 北京建设工程信息网站江苏企业网站建设
  • php电子商务网站建设wordpress新建的页面如何加xml
  • 去百度建网站外贸业务推广
  • 百度seo 站长工具网络营销课程个人总结3000字