并发编程(二):线程常用的方法

start和run

start方法

  • 功能说明:启动一个新线程,在新的线程运行run方法中的代码
  • start方法只是让线程进入就绪,里面代码不一定立刻运行,每个start方法只能调用一次,多次调用会出现(java.lang.IllegalThreadStateException)异常

start方法

  • 功能说明:新线程启动后会调用的方法
  • 如果在构造Thread对象中传递Runnable参数,则线程启动后会调用Runnable中的run方法,否则默认不执行任何操作。可以创建Thread的子类对象,来覆盖默认行为。
@Slf4j(topic = "ants.TestStart")
public class TestStart {
    public static void main(String[] args) {
        Thread t = new Thread("t1"){
            @Override
            public void run(){
                log.debug("执行run");
            }
        };
        t.start();
        log.debug("main 执行");
    }
}

sleep和yield

sleep

  • 调用sleep会让当前线程从Running进入Timed Waiting状态
  • 其他线程可以使用interrupt方法打断正在睡眠的线程,这时sleep方法会抛出InterruptedException
  • 睡眠结束后的线程未必会like得到执行
  • 建议用TimeUnit的sleep代替Thread的sleep来获得更好的可读性
@Slf4j(topic = "ants.TestSleep")
public class TestSleep {
    public static void main(String[] args) {
         //测试线程sleep
        Thread t1 = new Thread("t1") {
            @SneakyThrows
            @Override
            public void run() {
                Thread.sleep(2000);
                log.debug("t1线程停留2秒后执行");
            }
        };
        t1.start();
        log.debug("t1线程状态:{}",t1.getState());
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.debug("t1线程状态:{}",t1.getState());
    }
}
@Slf4j(topic = "ants.TestSleepInterrupt")
public class TestSleepInterrupt {
    public static void main(String[] args) throws InterruptedException {
        //睡眠线程调用interrupt,会抛出(InterruptedException)异常
        Thread t1 = new Thread("t1") {
            @Override
            public void run() {
                //建议使用 TimeUnit.SECONDS.sleep,睡眠时间更直观
                log.debug("enter sleep ...");
                try {
                    TimeUnit.SECONDS.sleep(2);
                    log.debug("t1线程停留2秒后执行");
                } catch (InterruptedException e) {
                    log.debug("sleep interrupt ...");
                    e.printStackTrace();
                }
            }
        };
        t1.start();
        Thread.sleep(1000);
        log.debug(" t1 interrupt...");
        t1.interrupt();

    }
}

yield

  • 调用yield会让当前线程从Running进入Runnable状态,然后调度执行其他同优先级的线程。如果这时没有同优先级的线程,name不能保证让当前线程暂停的效果。
  • 具体的实现依赖于操作系统的任务调度器
  • yield代码测试没有那么明显,首先保证两个线程优先级一致,但是t1线程执行yield方法后,虽然从Running进入Runnable状态,但是很有可能再次获得CPU时间片,下面这段代码理想状态下是,线程在执行0的倍数时,暂停当前线程,执行其他线程。比如t1执行到(i=10),t1不在执行下一次打印,让t2打印。
@Slf4j(topic = "ants.TestYield")
public class TestYield {

    public static void main(String[] args)  {
        Test t1 = new Test("t1");
        Test t2 = new Test("t2");
        t1.start();
        t2.start();
    }
}
@Slf4j(topic = "ants.Test")
class Test extends Thread{
    public Test(String name){
        super(name);
    }

    @Override
    public void run() {
        for(int i = 1;i <=100; i++) {
            log.debug("t1线程执行第{}循环",i);
            if(i == 0)
                Thread.yield();
        }
    }
}

sleep与yield对比

  • 让其他线程执行:sleep会明确在睡眠时间让其他线程执行,yield会和runnable状态线程得到执行可能
  • 状态不同:执行sleep后线程状态变为timed waiting,执行yield后线程状态变为runnable
  • 明确的时间:sleep会有明确时间(睡眠时长)不会执行,因为任务调度器不会把CPU时间片分给状态timed waiting;yield可能会得到时间片,立即执行。

线程优先级

  • 线程优先级会提示调度器优先调度该线程,但仅仅是一个提示,调度器可以忽略
  • 如果cpu比较忙,那么优先级高的线程将会获得更多的而时间片,但cpu空闲时,优先级几乎没作用
@Slf4j(topic = "ants.TestPriority")
public class TestPriority {
    public static void main(String[] args) {
        Thread t1 = new Thread("t1") {
            @Override
            public void run() {
                int count=0;
                while(true){
                    log.debug("t1线程count值:{}",count++);
                }
            }
        };
        Thread t2 = new Thread("t2") {
            @Override
            public void run() {
                int count=0;
                while(true){
                    //yield(); //注释该行,发现打印结果count值接近,打开后t1线程获得CPU时间片多,count值大
                    log.debug("t2线程count值:{}",count++);
                }
            }
        };
        //t1.setPriority(Thread.MAX_PRIORITY);//单核CPU测试线程优先级效果明显
        //t2.setPriority(Thread.MIN_PRIORITY);
        t1.start();
        t2.start();

    }
}

防止CPU只用100%

  1. sleep线程睡眠,适合无锁场景
  2. wait或条件变量控制,都需要加锁,需要相关唤醒操作,一般用户同步场景

join

  • 调用该线程的线程同步,程序才会继续向下执行
  • join可以做限时通过,join(1000)1000毫秒后,如果线程没结束,继续向下执行

interrupt、isInterrupted、interrupt

  • interrupt设置打断标记,正常线程调用方法后,打断状态是true,调用wait、sleep、join线程的打断标记是false
  • isInterrupted 查看线程状态
  • interrupted 查看线程状态,并设置打断标记为false
@Slf4j(topic = "ants.TestInterrupt")
public class TestInterrupt {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread("t1") {
            //进入sleep wait 、join线程,异常标记为false
            @Override
            public void run() {
                log.debug("t1 interrupt");
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    log.debug("Thread.currentThread().interrupt() before:{}",Thread.currentThread().isInterrupted());
                    e.printStackTrace();
                    Thread.currentThread().interrupt();
                    log.debug("Thread.currentThread().interrupt():{}",Thread.currentThread().isInterrupted());
                }
            }
        };
        Thread t2 = new Thread("t2") {
            //正常执行的线程,打断标记为true
            @Override
            public void run() {
                log.debug("t2 interrupt");
                while(true){

                }

            }
        };
        Thread t3 = new Thread("t3") {
            //线程优雅关闭
            @Override
            public void run() {
                boolean flag = true;
                while(flag){
                    if(Thread.currentThread().isInterrupted()){
                        log.debug("t3 interrupt");
                        flag=false;
                    }
                }
                //处理退出循环后续逻辑
                log.debug("t3 退出循环");

            }
        };
        t1.start();
        Thread.sleep(1000);
        t1.interrupt();
        Thread.sleep(1000);
        log.debug("t1线程的打断标记:{}",t1.isInterrupted());
        log.debug("-------------------");
       t2.start();
        Thread.sleep(1000);
        t2.interrupt();
        Thread.sleep(1000);
        log.debug("t2线程的打断标记:{}",t2.isInterrupted());
        log.debug("-------------------");
        t3.start();
        Thread.sleep(1000);
        t3.interrupt();
        Thread.sleep(1000);

        log.debug("t3线程执行结束后打断标记:{}",t3.isInterrupted());
    }
}

park unpark

  • 线程调用LockSupport中的park方法,当前线程会停下来执行,调用线程的interrupt,将打断标记置为false后,继续执行后续代码
@Slf4j(topic = "ants.TestPark")
public class TestPark {
    public static void main(String[] args) {
        Thread t1 = new Thread("t1") {
            @Override
            public void run() {
                log.debug("t1 线程执行中-----");
                LockSupport.park();
                //log.debug("t1打断标记:{}",Thread.currentThread().isInterrupted());//不改变打断标记值
                log.debug("t1打断标记:{}",Thread.interrupted());//将打断标记置为false
                log.debug("t1 park  后面代码-----");
                LockSupport.park();
                log.debug("t1 再次 park  后面代码-----");

            }
        };
        t1.start();
        t1.interrupt();//打断正在执行的park线程
    }
}

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

推荐阅读更多精彩内容

  • Java多线程学习 [-] 一扩展javalangThread类 二实现javalangRunnable接口 三T...
    影驰阅读 2,946评论 1 18
  • 本文主要讲了java中多线程的使用方法、线程同步、线程数据传递、线程状态及相应的一些线程函数用法、概述等。 首先讲...
    李欣阳阅读 2,433评论 1 15
  • 林炳文Evankaka原创作品。转载自http://blog.csdn.net/evankaka 本文主要讲了ja...
    ccq_inori阅读 642评论 0 4
  • 本文主要介绍线程的定义,创建,使用,停止,状态图和常用方法。主要用于概念扫盲和梳理。多进程是指操作系统能同时运行多...
    stoneyang94阅读 1,178评论 2 5
  • 1、基础梳理 进程和线程。1). 进程是操作系统正在执行的不同应用程序的一个实例,线程是操作系统分配处理器时间的基...
    开发者如是说阅读 343评论 0 5