(一)多线程基础


1、基本概念

1.进程:正在进行中的程序,指程序在内存中开辟了一块空间;进程持有资源(共享内存、共享文件)和线程,具有动态性。

2.线程:负责程序执行的一条执行路径,该路径也被称为执行单元。进程的执行实际上是线程在执行,一个进程至少会有一个线程,当一个进程中有多个线程时,就是多线程程序,这些线程共享进程资源。

3.多线程意义:最主要的目的是实现同时执行的不同功能的效果,虽然不一定能提高效率,但可以合理的利用cpu资源。

4.任务:每个线程需要执行的代码被称为任务代码,且都有其存储位置。例如下面代码示例中:

主线程的任务代码存储在main()方法中
垃圾回收线程的任务代码存储在finalize()方法中

线程是随着任务代码的执行才存在的,且随着任务代码的结束而消失。


2、线程示例

通过利用垃圾回收机制证明JVM虚拟机是多线程程序

//创建该类用于产生垃圾
class garbage {
    /*
     * 考虑到所有的对象都可以被当做垃圾回收 
     * 因此垃圾回收机制的代码应该在所有类的父类的当中 
     * 即Object类中的finalize()方法
     * 重写该方法便于验证是否执行
     */
    public void finalize() {
        System.out.println("垃圾回收线程抢占CPU成功!");
    }
}

public class Demo1 {

    public static void main(String[] args) {
        /*
         * main()方法是程序的入口 
         * 因此以下代码都属于主线程部分
         */
        
        /*
         * 创建多个匿名对象 
         * 匿名对象在创建后就直接成为了垃圾 
         * 因此可触发垃圾回收机制
         */
        new garbage();
        new garbage();
        new garbage();
        new garbage();
        new garbage();

        /*
         * 因为垃圾量少且垃圾回收机制的优先级本身就低 
         * 因此使用System类中的强制垃圾回收方法gc() 
         * 这样主线程运行至此就会启动垃圾回收线程
         * 执行finalize()方法
         */
        System.gc();// 垃圾回收线程启动,此时同时存在2个线程
        System.out.println("主线程抢占CPU成功!");

    }

}

结果如下:
由于线程之间在争抢cpu,因此多线程程序的执行结果是不确定的,这就是多线程程序的随机性。


3、Thread类

在Java中,线程同样实现了面向对象,那就是Thread类,使用该类创建新执行线程有两种方法:

1.将类声明为Thread的子类。该子类重写Thread类的run()方法。接下来可以分配并启动该子类的实例。如果直接创建Thread类的对象并用对象调用start()方法,将不会有任何结果,因为任务代码要求必须写在run()方法中,而Thread类中的run()方法没有任何功能。
该方法不建议使用,仅了解即可!


// 实现两位学生同时回答问题的效果

class Student extends Thread {
    // 创建Student类继承Thread类
    private String name;

    public Student() {
        super();
    }

    public Student(String name) {
        super();
        this.name = name;
    }

    public void run() {
        /*
         * 之前讲过 
         * 每个线程需要执行的代码被称为任务代码,且都有其存储位置
         * 此处重写run()方法 
         * 就是创建任务代码
         * 因此run()方法也就是任务代码的存储位置
         */
        for (int i = 1; i <= 10; i++) {
            System.out.println(name + "回答了第" + i + "个问题");
            /*
             * currentThread()是一个静态方法 
             * 返回值是当前正在执行的线程的对象 
             * 再调用对象的getName()方法
             * 显示当前线程的名称
             */
            // System.out.println(Thread.currentThread().getName()+"回答了第"+i+"个问题");
        }
    }

}

public class Demo2 {

    public static void main(String[] args) {
        /*
         * 由于Student类继承了Thread类 
         * 每次创建Student子类对象时 
         * 就相当于新创建了一个线程
         */
        Student s1 = new Student("Tom");
        /*
         * 主线程运行至创建s2对象 
         * 此时整个程序只有2个线程 
         * 主线程以及垃圾回收线程 
         * 两个子线程目前仅仅是创建 
         * 尚未启动,因此不会抢占cpu
         */
        Student s2 = new Student("Mike");
        /*
         * run()方法只是普通的方法调用 
         * 而start()方法可以启动线程 
         * 主线程的任务代码存储在main()方法中
         * 子线程的任务代码存储在run()方法中
         */
        s1.start();// 主线程执行至此,同时存在3个线程
        s2.start();// 主线程执行至此,同时存在4个线程

        System.out.println("提问!");
        // 显示主线程名称
        // System.out.println(Thread.currentThread().getName()+"提问!");

    }

}

注意:
  线程与线程之间在内存中是相互独立的,例如当一个线程发生异常时,其他线程不受影响,会继续执行。每个线程在栈中都有一块内存,当线程执行完自己的任务代码,就从栈中出栈,当所有线程都结束了,整个进程才会结束。

结果如下:
虽然主线程在执行最后一行输出代码之前已经启动了子线程,但子线程并未成功争抢到cpu,因此结果是主线程持续抢占cpu打印了“提问!”,之后才是子线程开始互相争抢cpu,这就表示子线程并不是随着启动就能占有cpu。

显示线程名称的结果如下:
主线程名字:main
子线程名字:Thread-编号,编号从0开始

2.声明实现Runnable接口的类,并重写run()方法,该类只是为了描述线程任务,实现了线程任务的面向对象,从而实现了线程任务和线程对象的分离,使线程执行的任务更加灵活,只要是实现了Runnable接口的类的对象,都可以作为参数传给Thread类的构造方法并启动线程;而且该类实现了接口的同时,还可以继承其他父类。
创建线程常使用此方法!

//实现四个窗口同时买票
class Ticket implements Runnable {
    // 创建Ticket类实现了Runnable接口

    // 定义总共50张票
    private int num = 50;

    // 重写Runnable接口中的run()方法,省略循环
    public void run() {
        if (num > 0) {
            System.out.println("窗口" + Thread.currentThread().getName() + "卖了第" + num-- + "张票");
        }
    }
}

public class Demo3 {

    public static void main(String[] args) {
        // 创建实现了Runnable接口的Ticket类的对象
        Ticket t = new Ticket();
        /*
         * 创建Thread类的对象,也就是创建了线程 
         * 把实现了Runnable接口的Ticket类的对象作为参数传递给Thread类的构造方法
         */

        Thread t1 = new Thread(t);
        Thread t2 = new Thread(t);
        Thread t3 = new Thread(t);
        Thread t4 = new Thread(t);

        t1.start();
        t2.start();
        t3.start();
        t4.start();

    }

}

4、线程的生命周期


版权声明:欢迎转载,欢迎扩散,但转载时请标明作者以及原文出处,谢谢合作!             ↓↓↓
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,053评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,527评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,779评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,685评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,699评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,609评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,989评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,654评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,890评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,634评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,716评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,394评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,976评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,950评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,191评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,849评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,458评论 2 342

推荐阅读更多精彩内容