复学day13

线程状态

一个线程在运行时的生命周期可大体分为五种状态:创建状态[new Thread(),线程对象一旦创建就进入到创建状态]、就绪状态[当调用start()方法,线程立即进入就绪状态,此时并不意味着立即执行]、阻塞状态[当调用sleep、wait或同步锁定时,线程进入阻塞状态]、运行状态[线程真正执行线程体代码块的时段]、死亡状态[中断或结束,死亡后不能再启动],要确定一个线程的当前状态,可调用getState方法。

(修改:查阅资料后,补充中断,相关语句,interrupt、interrupted、isInterrupted,扩展:每一个线程都具有boolean标志,调用interrupt方法后该boolean置位[调用interrupted方法会清除该线程的中断状态]。每个线程都应该不时地检查这个标志,以此判断线程是否中断。判断语句Thread.currentThread.isInterrupt来判断是否为中断状态,并不会改变中断状态)ps:中断一个线程不过是引起注意,被中断的线程可以决定如何响应中断。

停止线程

JDK提供有停止线程的两个方法stop()、destory(),但是这两种方法均不做推荐,已经废弃,采用这种强行停止的方法会有线程的安全隐患,推荐线程自己停止。

由此,我们可以采用一个标志位来安全地停止线程。

public class TestStop implements Runnable{
    private boolean flag = true;
    @override
    public void run(){
        while(flag){
            //线程体
            ...
        }
    }
	public void stop(){
        this.flag = false;
    }
    
    //===========
    public static void main(String args[]){
        TestStop ts = new TestStop();
        new Thread(ts).start();
        
        for(int i = 0;i < 500;i++){
            System.out.println("main"+i);
            if(i==300){
                ts.stop();
                System.out.println("线程停止了");
            }
        }
    }
}

线程休眠/sleep

sleep指定当前线程阻塞的毫秒数 1000ms = 1s,该方法存在异常(InterruptedException)。当sleep时间达到后线程进入就绪状态。sleep()方法主要有两个作用:1、模拟网络延迟,2模拟倒计时。

//打印当前系统时间
Date startTime = new Date(System.currentTimeMillis());//获取当前时间
while(true){
    try {
        Thread.sleep(1000);
        System.out.println(new SimpleDateFormat("HH:mm:ss").format(startTime));
        startTime = new Date(System.currentTimeMillis());//更新当前时间
    }catch(InterruptedException e){
        e.printStackTrace();
    }
}

//模拟倒计时
public static void tenDown() throws InterruptedException{
    int num = 10;
    while(true){
        Thread.sleep(1000);
        System.out.println(num--);
        if(num <= 0){
            break;
        }
    }
}

线程礼让/Yield

礼让线程,让当前正在执行的线程暂停,但不阻塞,使线程从运行状态转为就绪状态,然后让cpu重新调度 / / ps:类似两个线程比赛重开

Join

join合并线程,待此线程执行完成后,再执行其他线程,其他线程阻塞。 //ps:插队

public class TestJoin implements Runnable{
    @Override
    public void run(){
        Thread.sleep(1000);
        for(int i = 0;i < 200; i++){
            System.out.println("join插入");
        }
    }
    
    public static void main(String args[]){
        TestJoin tj = new TestJoin;
        Thread thread = new Thread(tj);
        thread.start();
        
        for(int i = 0;i < 500; i++){
            if(i == 200){
                thread.join();
            }
            System.out.println("main")
        }
    }
}

线程优先级

Java提供了一个线程调度器来监控程序中启动后进入就绪状态的所有线程,线程调度器会按照优先级决定应该执行哪个线程。

线程的优先级用数字表示,范围1~10.

​ Thread.MIN_PRIORITY = 1;

​ Thread.MAX_PRIORITY = 10;

​ Thread.NORM_PRIORITY = 5;

//使用以下方式改变或获取优先级
	.getPriority()   .setPriority(int xxx)

优先级低只是意味着获得调度的概率低,并不是优先级低就不会被调用,也是看cpu调度

守护(daemon)线程

java中有两类线程:User Thread(用户线程) Daemon Thread(守护线程)

两者的区别在于jvm虚拟机何时离开。

当存在任何一个用户线程还在时,jvm是不会离开的;但如果只剩下守护线程未离开,则jvm是可以离开的。(守护线程有点类似辅助的作用,当公司的人全部离开后,保安再下班)

//制作守护线程的方法
.setDaemon(true)

用户线程:简单理解平时用到的普通线程均是用户线程,在java程序中创建的线程,便是用户线程。

用户线程的标准定义:不需要内核支持而在用户程序中实现的线程,其不依赖于操作系统核心,应用进程利用线程库提供创建、同步、调度和管理线程的函数来控制用户线程。

守护线程:用来服务于其他线程的线程,比如垃圾回收线程。

多线同步

在多个线程操作同一个资源时便会发生并发的问题。再具体,多个线程访问同一个对象,并且某些线程还想要修改这个对象,此时,我们便需要线程同步解决这个问题。

线程同步,其实本质接近一种等待机制,多个线程访问同一个对象时,那么这些线程便进入这个对象的等待池形成队列(类似排队),此时引入锁的机制,每个对象都有一把锁(synchronized,当一个线程获得对象的排他锁,独占资源,其他线程必须等待),锁使得在等待池队列的多个线程一个一个依次执行。

锁机制使得线程有序执行,但是也带来了一些缺点:在多线程竞争下,加锁、释放锁会导致比较多的上下文切换,引起性能问题;如果一个优先级较高的线程等待一个优先级低的线程释放锁,那么会导致优先级倒置,这个也是性能问题。

posted @ 2020-11-25 19:52  何安生  阅读(103)  评论(0)    收藏  举报