首页 » SEO优化 » php中线程start技巧_Java高并发编程剖析线程启动的start方法

php中线程start技巧_Java高并发编程剖析线程启动的start方法

访客 2024-12-08 0

扫一扫用手机浏览

文章目录 [+]

在之前剖析中,我们知道线程从NEW状态进入到RUNNABLE装须要调用start()方法,但是当线程调用完start()方法之后到底进行了那些操作呢?在之前的例子中,我们将业务逻辑代码写到了run()方法中,但是实际上实行线程调用的时候却是实行的是线程的start()方法,两者之间又有什么联系呢?

下面我们就来剖析一下。

php中线程start技巧_Java高并发编程剖析线程启动的start方法

Thread start方法源码剖析

Thread 类的start方法源码如下所示。

php中线程start技巧_Java高并发编程剖析线程启动的start方法
(图片来自网络侵删)

public synchronized void start() { if (threadStatus != 0) throw new IllegalThreadStateException(); group.add(this); boolean started = false; try { start0(); started = true; } finally { try { if (!started) { group.threadStartFailed(this); } } catch (Throwable ignore) { } } }

通过源码可以看出来,源码逻辑相比拟较大略,个中最紧张的一个代码便是start0()方法。
在源码中可以看到start0(),代码如下所示。

private native void start0();

也便是说,在我们调用了start()方法之后,会调用start0()方法,还是没有创造run()方法是什么时候被实行的,但是查看JDK的文档之后,我们会知道,实在这里的start0()方法实在是通过JNI技能进行调用的,而run()方法也是被JNI的start0()方法。
阅读源码之后会有如下的一些问题。

当我们new一个线程之后,threadStatus 属性的值该当是默认为0的,当不即是0的时候就会抛出非常。
这个在源码中说得比较清楚。
threadStatus为零表示这个当前状态是NEW根据threadStatus的状态可以知道,不能进行两次启动线程操作,也便是说同一个线程工具,不能两次重复调用start()方法,否则就会抛出非常。
线程启动之后就会被加入到一个线程组中,后续会说到线程组干系的观点。
当一个线程结束,进入到TERMINATED状态之后,是没有办法通过调用start()方法再次进入到RUNNABLE状态或者是RUNNING状态的。

模板设计模式在Thread中的利用

通过上面的剖析,可以知道,一个线程真正的逻辑实行代码是被放到run()方法中,常日情形下run()方法便是我们编写线程实行逻辑的地方,这也便是为什么我们要重写run()方法,用start()启动的线程。
Thread类中的run方法如下。

@Override public void run() { if (target != null) { target.run(); } }

默认情形下,这个方法可以看做是一个空方法。
方法体中没有任何代码。

不难创造在Thread中的run()方法start()方法便是一个非常范例的模板设计模式,父类编写算法构造代码,子类卖力按照对应的模板进行实现。
下面来看一个小例子

模板设计模式小例子

首先创建一个输出的接口类,这个类便是制订输出的规则,代码如下

public interface PrintMessage { abstract void print();}

接下来便是其子类要实现这个输出了。
代码如下

public class Repoter implements PrintMessage { public void printNews() { print(); } @Override public void print() { System.out.println("show news"); }}

编写测试类main方法。

public class TemplateMain { public static void main(String[] args) { Repoter repoter = new Repoter(){ @Override public void print() { System.out.println("这个是一个设计模板方法"); } }; repoter.printNews(); }}

这里会看到全体的模式都是按照Thread的模式来进行。
个中的print()方法和printNews()方法就类似于Thread类的run()方法和start()方法。
这样一来,父类只须要见告子类须要做的事情是什么,而不须要知道至于子类如何实现,终极便是子类的事情了。

大略的仿照一个叫号系统

很多人都有过存款或者买票的体验,他们有一个共同的特点便是须要排队叫号。
实在这种机制办理了很多的问题。
例如可以做到限流,可以合理的分配处理职员的位置,可以很好的办理了由于排队引起的社会抵牾。
同时也减轻了业务员、管理职员的压力

我们这里大略的仿照有四个窗口的叫号系统。
四个窗口就相称于有四个线程。
通过这四个窗口来仿照50人排队的场景。

public class TicketWindow extends Thread { private final String name; private static final int MAX = 50; private int index = 1; public TicketWindow(String name) { this.name = name; } @Override public void run() { while (index<MAX){ System.out.println(name+" 号柜台,出号 "+index++); } } public static void main(String[] args){ TicketWindow ticketWindow1 = new TicketWindow("一"); ticketWindow1.start(); TicketWindow ticketWindow2 = new TicketWindow("二"); ticketWindow2.start(); TicketWindow ticketWindow3 = new TicketWindow("三"); ticketWindow3.start(); TicketWindow ticketWindow4 = new TicketWindow("四"); ticketWindow4.start(); }}

运行上面代码之后会看到如下的结果,大略地剖析之后,会创造实在这是有问题的。
1号票被多个柜台出了。

为什么会涌现这样的问题,这便是每个线程实行的逻辑都不一样,新建了四个线程,每个线程的票号都是从0~50。
四个线程并没有操作同一个票号排序。
以是就会涌现上面这个问题。
那么我们如何去办理这个问题呢?我们想到了利用static 去润色 index变量的办法。
代码如下。

public class TicketWindow extends Thread { private final String name; private static final int MAX = 50; private static int index = 1; public TicketWindow(String name) { this.name = name; } @Override public void run() { while (index<MAX){ System.out.println(name+" 号柜台,出号 "+index++); } } public static void main(String[] args){ TicketWindow ticketWindow1 = new TicketWindow("一"); ticketWindow1.start(); TicketWindow ticketWindow2 = new TicketWindow("二"); ticketWindow2.start(); TicketWindow ticketWindow3 = new TicketWindow("三"); ticketWindow3.start(); TicketWindow ticketWindow4 = new TicketWindow("四"); ticketWindow4.start(); }}

经由修正之后,运行结果如下,这个时候看上去统统都就正常了。

通过对index进行static的润色,做到了多线程共享索引的操作。
看上去是知足了需求,但是实际上还是有很多的问题,如果共享索引的数据太大的时候,也会涌现线程安全的问题。
这个问题在后续的分享中会提到。
以是说static只能办理小问题,须要办理大问题的话还须要大手笔的办理方案。
在后续的分享中也会提到。
这里就先到这里,大家可以先消化一下Thread 的模板设计模式事理。

相关文章

php函数st技巧_PHP date 函数

PHP date( 函数PHP date( 函数可把韶光戳格式化为可读性更好的日期和韶光。韶光戳是一个字符序列,表示一定的事宜...

SEO优化 2024-12-09 阅读0 评论0