Java线程学习(一)

  • Java使用Thread类代表线程,所有的线程对象都必须是Tread类或其子类的实例。每条线程的作用是完成一定的任务,实际上就是执行一段程序流。Java使用run方法来封装这样的一段程序流。
    通过继承Thread类来创建并启动多线程的步骤如下:
  1. 定义Thread类的子类,并重写该类的run方法,该run方法的方法体就是代表了线程需要完成的任务。因此我们经常把run方法称为线程执行体。
  2. 创建Thread子类的实例,即使创建了线程对象
  3. 用线程对象的start方法来启动该线程
public class FirstThread extends Thread{
        private int i;
        public void run(){
            for(;i < 100; i ++){
                //当线程类继承Thread类时,可以直接调用getName()方法来返回当前线程的名字
                //如果想获取当前线程,直接使用this即可
                //Thread对象的getName()返回该线程的名字
                System.out.println(getName() + "" + i);
            }
        }
        public static void main(){
                for(int i = 0; I < 100; i++){
                        System.out.println(Thread.currentThread().getName() + "" + i);
                        if (i == 20){
                                new FirstTread().start();
                                new FirstTread().start();
                        }
                }
        }
}
Thread.JPG

注意一:Thread-0 和Thread -1两条线程输出的i变量不连续,i变量是FirstThread的实例属性,而不是局部变量,但是因为程序每次创建线程对象时都需要创建一个FirstThread对象,所以不共享该实例属性。使用继承Thread类的方法来创建线程类,多条线程之间无法共享线程类的实例变量。
注意二:启动线程应该使用start方法,而不是run方法。永远不要调用线程对象的run方法。调用start方法来启动线程,系统会把该run方法当成线程执行体来处理。但如果直接调用线程对象的run方法,系统指挥把线程对象当作一个普通的对象,而run方法也只是普通方法,而不是线程执行体。

package com.imooc;

public class MyThread extends Thread{
    private int i;
    public void run(){
        for (; i < 100; i++){
            System.out.println(Thread.currentThread().getName() + " " + i);
        }
    }
    
    public static void main(String[] args){
        for (int i = 0; i < 100; i++){
            System.out.println(Thread.currentThread().getName() + " " + i);
            if (i ==20){
                new MyThread().run();
                new MyThread().run();
            }
        }
    }
}

  • 实现Runnable接口创建线程
    创建Runnable对象作为线程对象的target。使用这种方法时,两条线程的i变量是连续的,因为两条线程使用的是同一个target,即同一个Runnable对象。
public class SecondThread implements Runnable {

    private int i;

    @Override
    public void run() {
        // TODO Auto-generated method stub
        for(; i < 100; i ++){
            System.out.println(Thread.currentThread().getName() + " " + i);  //注意三
        }
    }

    public static void main(String[] args){
        for(int i = 0; i < 100; i++){
            System.out.println(Thread.currentThread().getName() + " " + i);
            if (i == 20){
                SecondThread st = new SecondThread();
                new Thread(st, "新线程1").start();
                new Thread(st, "新线程2").start();
            }
        }
    }
}

注意三:
使用Runnable接口时,必须使用Thread.currentThread.getName()方法来查看当前线程的名字

  • 线程的生命周期
  1. 新建:new关键字创建了一个线程后,该线程就处于新建状态。此时和其他Java对象一样,仅仅由虚拟机为其分配了内存,并初始化了成员变量的值。没有表现出任何线程的动态特征。
  2. 就绪:当线程对象调用了start()方法后,该线程就处于就绪状态,Java虚拟机会为其创建方法调用栈,程序计数器,但是此时还没有运行,只是代表着该线程可以运行了。至于何时运行,取决于JVM里线程调度器的调度。
  3. 运行:如果就绪的线程获得了CPU,开始执行run方法的线程执行体,此时线程处于运行状态
  4. 阻塞:
    发生以下情况时,线程进入阻塞:
  • 线程调用sleep方法主动放弃处理器资源
  • 等待资源时
  • 程序调用了线程的suspend方法将该线程挂起(容易导致死锁)
针对以上的情况,发生特定的情况将可以接触上面的阻塞,让该线程重新进入就绪状态:
- 调用的sleep方法经过了指定的时间
- 等待的资源已获得
- 处于挂起状态的线程被调用了resume()回复方法。
  1. 死亡:我们可以通过调用线程对象的isAlive()方法来检测线程是否死亡,当线程处于就绪,运行,阻塞时,该方法返回true;处于新建,死亡时,该方法返回false。注意,不要试图对一个已经死亡的线程调用start()方法,否则会产生IllegalThreadStateException异常。
    线程会以以下三种方式之一结束,结束后就处于死亡状态;
  • run()方法执行完成,线程正常结束
  • 线程抛出一个未捕获的Exception或Error
  • 直接调用该线程的stop()来结束该线程-该方法容易导致死锁
  • 控制线程
  1. join线程:当在某个程序执行流中调用A线程的join()方法时,调用线程将被阻塞,直到被join()方法加入的A线程完成为止。
  2. 后台线程:这种线程在后台运行,他的任务是为其他的线程提供服务。如果所有的前台线程死亡,后台线程会自动死亡。调用Thread对象的setDaemon(true)方法可将指定线程设置成后台线程,但是注意,setDeamon(true)必须在start()方法前调用,否则IllegalThreadStateException异常。
  3. 线程睡眠sleep()方法:通过调用Thread类的静sleep方法,可以让当前正在执行的线程暂定指定的时间,并进入阻塞状态Thread.sleep(1000);,在之后,线程自动进入就绪状态。
  4. 线程让步yield方法:这个方法也是Thread提供的一个静态方法,它将正在执行的线程自动转入就绪状态(但不阻塞)。当某个线程调用了yield方法暂停后,线程调度器完全可能再次将其调用出来执行。但是,当某个线程调用了yield()方法暂停后,只有优先级大于、等于当前线程的就绪状态的线程才会获得执行的机会。
  5. 改变线程的优先级:`thread.setPriority(MAX_PRIORITY)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容