Java 多线程编程核心技术--第一章

来源:互联网 发布:什么是淘宝店铺引流 编辑:程序博客网 时间:2024/06/05 11:01

进程

进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。在早期面向进程设计的计算机结构中,进程是程序的基本执行实体;在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体。

线程

线程,有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元。一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。另外,线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行。由于线程之间的相互制约,致使线程在运行中呈现出间断性。线程也有就绪、阻塞和运行三种基本状态。就绪状态是指线程具备运行的所有条件,逻辑上可以运行,在等待处理机;运行状态是指线程占有处理机正在运行;阻塞状态是指线程在等待一个事件(如某个信号量),逻辑上不可执行。每一个程序都至少有一个线程,若程序只有一个线程,那就是程序本身。

多线程

线程是程序中一个单一的顺序控制流程。进程内一个相对独立的、可调度的执行单元,是系统独立调度和分派CPU的基本单位指运行中的程序的调度单位。在单个程序中同时运行多个线程完成不同的工作,称为多线程。

使用多线程

package chapter_one;public class callMainMethodMainThread {    public static void main(String[] args) {        System.out.println(Thread.currentThread().getName());    }}

输出:main
表示:一个名称为 main 的线程正在执行 main() 方法中的代码。

实现多线程编程的方式主要有两种:
1.继承Thread类

class Thread implements Runnable {}

如上所示,Thread 类实现了 Runnable 接口。
使用继承 Thread 类的方式创建新线程的最大局限就是不支持多继承。

package chapter_one;/** * 继承 Thread 类 实现多线程 */public class MyThread extends Thread {    @Override    public void run() {        super.run();        System.out.println("MyThread");    }}
package chapter_one;public class Run {    public static void main(String[] args) {        MyThread myThread = new MyThread();        myThread.start();        System.out.println("运行结束!");    }}

输出:
运行结束!
MyThread
这也说明了使用多线程技术时,代码的运行结果与代码执行的顺序或调用顺序是无关的。
线程是一个子任务,CPU以不确定的方式,或者说是以随机的时间来调用线程中的run方法,所以就会出现先打印“运行结束!”后输出“MyThread”这样的结果了。

Thread.java类中的start()方法通知“线程规划器”此线程已经准备就绪,等待调用线程对象的run()方法。这个过程其实就是让系统安排一个时间来调用Thread中的run()方法,也就是使线程得到运行,启动线程,具有异步执行的效果。如果调用代码Thread.run()就不是异步执行了,而是同步,那么此线程对象并不交给“线程规划器”来进行处理,而是由main主线程来调用run()方法,也就是必须等run()方法中的代码执行完后才可以执行后面的代码。
测试:

package chapter_one;/** * 继承 Thread 类 实现多线程 */public class MyThread extends Thread {    private int i;    public MyThread(int i) {        this.i = i;    }    @Override    public void run() {        super.run();        System.out.println("i = " + i);        System.out.println(Thread.currentThread().getName());    }}
package chapter_one;public class Run {    public static void main(String[] args) {        MyThread myThread1 = new MyThread(1);        MyThread myThread2 = new MyThread(2);        MyThread myThread3 = new MyThread(3);        MyThread myThread4 = new MyThread(4);        MyThread myThread5 = new MyThread(5);        MyThread myThread6 = new MyThread(6);        MyThread myThread7 = new MyThread(7);        MyThread myThread8 = new MyThread(8);        MyThread myThread9 = new MyThread(9);        MyThread myThread10 = new MyThread(10);        MyThread myThread11 = new MyThread(11);        MyThread myThread12 = new MyThread(12);        MyThread myThread13 = new MyThread(13);        MyThread myThread14 = new MyThread(14);        MyThread myThread15 = new MyThread(15);        myThread1.start();        myThread2.start();        myThread3.start();        myThread4.start();        myThread5.start();        myThread6.start();        myThread7.start();        myThread8.start();        myThread9.start();        myThread10.start();        myThread11.start();        myThread12.start();        myThread13.start();        myThread14.start();        myThread15.start();        /*myThread1.run();        myThread2.run();        myThread3.run();        myThread4.run();        myThread5.run();        myThread6.run();        myThread7.run();        myThread8.run();        myThread9.run();        myThread10.run();        myThread11.run();        myThread12.run();        myThread13.run();        myThread14.run();        myThread15.run();*/    }}

输出:

i = 1i = 2i = 3i = 4i = 5i = 6i = 7i = 8i = 9i = 10i = 11i = 12i = 13i = 15i = 14

证明执行start()方法的顺序不代表线程启动的顺序。
当我们使用myThread*.run(); 来执行线程时则是顺序执行的,且是由main线程来执行的。

2.实现Runnable接口

package chapter_one;public class MyRunnable implements Runnable{    @Override    public void run() {        System.out.println("MyRunnable::run");    }}
import chapter_one.MyRunnable;import org.junit.Test;public class T {    @Test    public void testMyRunnable() {        Runnable runnable = new MyRunnable();        Thread thread = new Thread(runnable);        thread.run();    }}
package java.lang;/** * Runnable 接口应该由那些打算通过某一线程执行其实例的类来实现 * 实现类必须定义一个名称为 run() 的无参数方法 * 设计该接口的目的是为希望在活动时执行代码的对象提供一个公共协议 * 例如,Thread 类实现了 Runnable。激活的意思是说某个线程已启动并且尚未停止 * 此外,Runnable 为非 Thread 子类的类提供了一种激活方式 * 通过实例化某个 Thread 实例并将自身作为运行目标,就可以运行实现 Runnable 的类而无需创建 Thread 的子类 * 大多数情况下,如果只想重写 run() 方法,而不重写其他 Thread 方法,那么应使用 Runnable 接口 * 这很重要,因为除非程序员打算修改或增强类的基本行为,否则不应为该类创建子类 *  */@FunctionalInterfacepublic interface Runnable {    /**     * 使用实现接口 Runnable 的对象创建一个线程时     * 启动该线程将导致在独立执行的线程中调用对象的 run 方法     * 方法 run 的常规协定是:它可以执行任何所需的操作     */    public abstract void run();}