1、创立线程的形式
线程创立形式是:继承 Thread 类,重写 run 办法。如下:
public class Task extends Thread{ @Override public void run() { System.out.println("线程执行了"); }}
客户端应用如下,应用线程对象的start办法启动线程:
public class Client { public static void main(String[] args) { System.out.println("主线程开始执行"); Task task = new Task(); task.start(); System.out.println("主线程执行完结"); }}
输入后果:
主线程开始执行
主线程执行完结
线程执行了
留神:
1、必须应用 start 办法启动线程,而不能应用run办法启动,应用run办法和一般的办法调用没啥区别,应用run办法调用操作系统不会创立线程。(start 和 run 办法的区别,其实是模板设计模式中的细节,如果理解模板设计模式,那么你就会豁然开朗)
2、一个线程对象只能启动一次。否则会报 IllegalThreadStateException
异样,这是因为线程有状态,启动线程之后,状态会更改,再次启动则会呈现谬误,源码如下:
public synchronized void start() { /** * A zero status value corresponds to state "NEW". */ if (threadStatus != 0) throw new IllegalThreadStateException();
实际上新创建的线程状态是 NEW 状态,启动之后便不是该状态,而 start 办法只能启动状态是 NEW 的线程。
2、其余形式创立线程
这里说的其余形式,其实还是应用下面的Thread类,只是应用形式有所不同,咱们能够应用外部类的形式。
public class Client { public static void main(String[] args) { System.out.println("主线程开始执行"); Thread thread = new Thread(){ @Override public void run() { System.out.println("线程执行了..."); } }; thread.start(); System.out.println("主线程执行完结"); }}
当然还能够应用匿名外部类。
public class Client { public static void main(String[] args) { System.out.println("主线程开始执行"); new Thread() { @Override public void run() { System.out.println("线程执行了..."); } }.start(); System.out.println("主线程执行完结"); }}
3、线程的生命周期
public enum State { /** * 线程还未启动,只存在于线程刚创立,未start之前 */ NEW, /** * 可运行的状态,这个状态的线程,曾经在虚拟机中执行了,然而这个"执行",不肯定是真的在运行, 也有可能是在期待CPU资源 */ RUNNABLE, /** * 阻塞状态,个别是期待其余线程的锁开释 */ BLOCKED, /** * 期待状态 */ WAITING, /** * 这个状态和WAITING状态的区别就是,这个状态的期待是有肯定时效的, * 即能够了解为WAITING状态期待的工夫是永恒的,即必须等到某个条件合乎能力持续往下走,否则线程不会被唤醒。 * 然而TIMED_WAITING,期待一段时间之后,会唤醒线程去从新获取锁。 */ TIMED_WAITING, /** * 线程执行完结之后的状态 */ TERMINATED; }
下面简略阐明了线程的状态,具体阐明后续章节再探讨。
4、模板设计模式
定义一个操作算法中的框架,而将这些步骤提早加载到子类中。模板办法模式使得子类能够不扭转一个算法的构造即可重定义该算法的某些特定步骤。
次要的实现形式是: 一次性实现一个算法的不变局部,并将可变的行为留给子类来实现,达到各子类中公共的行为被提取到一个公共父类中以防止代码反复、又能够变成子类达到不同成果的目标。
个别实现形式是:
- 新建一个抽象类。
- 编写模板办法,也就是对立调用的入口办法,该办法将会执行所有的流程。留神模板办法肯定要应用final关键字润饰,使得子类无奈重写,就不会批改模板的执行流程。
- 模板办法中的大部分办法是该类曾经实现的,多数办法的实现暂未可知,然而这些办法影响整体的执行流程,那么将这些办法申明为形象办法。
- 子类继承模板类,实现形象办法即可。
public abstract class Template { public final void start(){ method1(); method2(); method3(); method4(); } private void method1(){ System.out.println("method1 执行了"); } private void method2(){ System.out.println("method2 执行了"); } private void method4(){ System.out.println("method4 执行了"); } protected abstract void method3();}
下面是模板类,依照下面的编写流程来看,非常简略。
public class TemplateOne extends Template{ @Override protected void method3() { System.out.println("TemplateOne 执行了 method3"); }}
TemplateOne 是模板类的子类之一。
public class TemplateTwo extends Template { @Override protected void method3() { System.out.println("TemplateTwo 执行了 method3"); }}
TemplateTwo 是模板类的另一个子类。
客户端代码如下,通过后果咱们能够看出,对于不同的子类,因为继承了父类,大部分性能都是一样的,局部父类无奈实现的性能由子类去实现,不同的子类就实现了不同的性能。
public class Client { public static void main(String[] args) { Template template = new TemplateOne(); template.start(); System.out.println("########################"); template = new TemplateTwo(); template.start(); }}
后果如下:
method1 执行了
method2 执行了
TemplateOne 执行了 method3
method4 执行了
########################
method1 执行了
method2 执行了
TemplateTwo 执行了 method3
method4 执行了
5、Thread 类中的模板设计模式
首先看下 Thread 类中的 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) { } } } private native void start0();
这里的start办法内容不算多,然而是一个模板办法,外面进行了一系列流程解决,其中调用了 start0 办法,该办法是个本地办法,最终操作系统会调用到 run 办法。暂且把 start0 办法看作 run 办法,那么类比下下面的模板设计模式,是不是十分相似?
- start 办法是一个模板办法,是一系列操作的入口。(其实最好是应用final润饰)
- run 办法能够看作是模板中的形象办法,须要子类实现。
- 不同的子类重写了run办法解决了不同的事件,就是线程的不同利用,是模板的具体实现。