2020/4/20学习笔记day43

java-day43

Thread类中的构造器和核心方法

构造器:
//创建一个线程对象,默认的名字为Thread-0 1 2 3 4...
public Thread(){}
//创建一个线程对象,可以指定线程的名字
public Thread(String name){}
//创建一个线程对象,
Runnable实现对象中重写了run方法,run方 法中就是线程要
执行的代码
pub1ic Thread( Runnable target){}
//创建一个线程对象,指定Runnable实现类的同时还可以指定线程的名字
public Thread(Runnable target, String name){ }
核心方法:
//start方法可以启动一个线程对象,线程被启动后,会独立的自动运行run方法
//start方法中调用了start0方法来完成这个启动的工作。
public synchronized void start(){}
private native void start0();

//Thread类中的run方法是通过实行接口Runnable获取的。
//这个方法的作用就是指定当前线程的任务是什么
//所以都会重写run方法来指定线程要执行的任务。
public void run() {}



//把Thread类中的代码简化后:
public class Thread implements Runnable {
    private Runnable target;
    public Thread(Runnable target) {
        this.target = target;
    }
    public Thread(){

    }
    public void run() {
        if (target != null) {
            target.run();
        }
    }
}

//Runnable接口的代码:
public interface Runnable {
    public abstract void run();
}


线程状态

在这里插入图片描述

new:初始化状态
	start():线程从初始变成就绪状态
Runnable:就绪状态
Running:运行状态
	run():线程启动自动调用run方法
    sleep():睡眠
    join():连接  
    运行期间调用sleep、join方法,会进入阻塞状态
Otherwise Blocked:阻塞状态
    sleep() time out:睡眠事件结束
    join()
    interupt()
    阻塞状态下睡眠时间结束、连接结束或者被其他打断了就进入就绪状态
Dead:线程死亡状态 run方法运行结束
cpu时间片

​ 每一个线程在使用cpu的时候,都只能使用很短的时间,因为不能让一个线程把cpu给独占了,cpu是所有程序代码共享的计算机资源,所以一个线程在使用一个很短的时间后就必须把cpu给交出去,让别的线程去使用。 那么操作系统为了方便管理和调度cpu的共享使用,就把cpu的使用时间划分成了一个个很短的时间段,这个就称为cpu的时间片。

​ 默认情况,如果线程可以拿到一个cpu时间片的使用权,那么这个线程就可以在这个时间段中使用cpu来计算代码中要操作的数据。但是这个cpu时间片的一旦用完,那么线程就必须交出cpu的使用权,下一次另一个线程如果拿到一个cpu时间片的使用权,那么这个线程就可以使用cpu进行计算了。(将来这里还要考虑给代码加锁的问题)。

一般线程拿到cpu时间片的方式有俩种,一种是时间片轮换,另一种是时间片抢占。

时间片轮换,就是一个线程使用完,把cpu使用权交出去,然后下一个线程使用,一个个线程挨着来使用。

时间片抢占,所有要使用cpu的线程都可以抢夺cpu时间片的使用权,谁抢夺到了,那么谁就去使用cpu执行代码,时间片用完后交出cpu使用权,下一次的使用权,所有线程再重新抢夺。这种方式下,哪一个线程能拿到时间片的使用权,全靠概率。注意,默认环境下,都是采用的抢占式。

State

       /**
        * 尚未启动的线程的线程状态。(初始化状态)
        */
        NEW,

        /**
      	 *可运行(就绪)线程的线程状态。可运行程序中的线程
		 *状态正在Java虚拟机中执行,但它可能
		 *正在等待来自操作系统的其他资源
		 *例如处理器。
         */
        RUNNABLE,

        /**
         *等待监视器锁定时被阻止的线程的线程状态。
         *处于阻塞状态的线程正在等待监视器锁定
         *输入同步块/方法或
         *调用后重新输入同步的块/方法
		 *{@link Object#wait()Object.wait}。
         */
        BLOCKED,

        /**
         * 等待线程的线程状态。
         * 由于调用
         * 以下方法:
         * <ul>
         *   <li>{@link Object#wait() Object.wait} with no timeout</li>
         *   <li>{@link #join() Thread.join} with no timeout</li>
         *   <li>{@link LockSupport#park() LockSupport.park}</li>
         * </ul>
         *
         * <p>处于等待状态的线程正在等待另一个线程
         * 执行特定的动作。
         *
         *例如,调用了<tt>Object.wait()</tt>的线程
         *一个对象正在等待另一个线程调用
         *<tt>Object.notify()</tt>或<tt>Object.notifyAll()</tt>打开
         *那个东西。调用了thread.join()的线程
         *正在等待指定的线程终止。
         */
        WAITING,

        /**
         * 具有指定等待时间的等待线程的线程状态。
         * 由于调用
         * 具有指定正等待时间的以下方法:
         * <ul>
         *   <li>{@link #sleep Thread.sleep}</li>
         *   <li>{@link Object#wait(long) Object.wait} with timeout</li>
         *   <li>{@link #join(long) Thread.join} with timeout</li>
         *   <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
         *   <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
         * </ul>
         */
        TIMED_WAITING,

        /**
         *终止线程的线程状态(死亡状态)。
         *线程已完成执行。
         */
        TERMINATED;
t线程刚刚创建属于初始化状态
public class ThreadTest2 {
	
	public static void main(String[] args) {
		
		Thread t = new Thread() {
			@Override
			public void run() {
				//...
			}
		};
		System.out.println(t.getState());		
	}	
}

在这里插入图片描述

main线程速度太快,还没来得及给t线程机会运行,处于就绪状态
public class ThreadTest2 {
	
	public static void main(String[] args) {
		
		Thread t = new Thread() {
			@Override
			public void run() {
				//...
			}
		};
		t.start();
		System.out.println(t.getState());		
	}		
}

在这里插入图片描述

run方法执行完,进入死亡状态
public class ThreadTest2 {
	
	public static void main(String[] args) {
		
		Thread t = new Thread() {
			@Override
			public void run() {
				
			}
		};
		t.start();//启动t线程
		//给t线程拖延时间
		System.out.println("hello");
		System.out.println(t.getState());		
	}		
}

在这里插入图片描述

调用sleep处于有限期等待
public class ThreadTest2 {
	
	public static void main(String[] args) {
		
		Thread t = new Thread() {
			@Override
			public void run() {
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		};
		t.start();//启动t线程
		//给t线程拖延时间
		System.out.println("hello");
		System.out.println(t.getState());		
	}		
}

在这里插入图片描述

线程状态总结

在Thread类中,定义了一个枚举类型State,其中定义了线程的几种状态。

NEW 新建/初始化 状态

刚刚创建出的线程对象,还没有调用start方法的时候,属于这种状态。

特点:

线程没有存活
isAlive方法判断返回的是false
线程没有执行代码
线程不会抢夺CPU执行权
线程还没有被启动

RUNNABLE 可运行 状态

当线程对象调用start方法之后,就属于这种状态,这种状态包含俩种情况,第一种就是这个线程现在正在运行(is executing),那么它就属于RUNNABLE状态,第二种就是这个线程正在等待(be waiting)cpu的执行权,那么它也属于RUNNABLE状态。

特点:
线程存活
isAlive方法判断返回的是true
线程可以是正在运行代码
线程可以是没有在运行代码,但是可以抢夺CPU执行权

BLOCKED
WAITING
TIMED_WAITING "有限期"等待 状态

Thread类中的sleep(long)方法,Thread类中的join(long)方法被一个线程调用后,那么该线程就会进入到TIMED_WAITING状态。

特点:
线程存活
isAlive方法判断返回的是true
线程没有执行代码
线程不会抢夺CPU执行权
线程等指定的时间结束后会自动回到Runnable状态

TERMINATED 终止 状态

当一个线程把run方法全部执行完了,那么它就属于TERMINATED状态

特点:

线程死亡
isAlive方法判断返回的是false
线程没有执行代码
线程不会抢夺CPU执行权
线程不能重新启动,只有NEW状态下的线程才可以启动(start)

终止线程

线程运行完run方法后,会自动终止,并且被终止的线程就不能再使用。

如果线程的run方法还没有运行完,这时候是否可以终止线程?
Thread类有一个stop方法,可以终止线程,但是现在这个方法已经被标注为过时的方法,意思就是现在这个方法还在,但是不建议使用了,因为这个stop方法中存在安全隐患。

现在可以通过一个"标记变量"来控制线程结束

例如:

public class ThreadTest3 {
    public static void main(String[] args) {

        class MyThread extends Thread{
            private boolean stop;
            @Override
            public void run() {
                String name = Thread.currentThread().getName();
                while(!stop) {
                    System.out.println(name+": hello");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println(name+" 中的标记变量变为true,run方法即将结束运行,线程终止");
            }
            public void setStop(boolean stop) {
                this.stop = stop;
            }
        }


        MyThread t = new MyThread();

        t.start();


        try {
            //main线程调用 睡眠5000
            //睡醒后调用t线程中的方法改变标记变量,停止t线程的运行
            Thread.sleep(5000);
            t.setStop(true);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
isAlive方法,可以判断当前线程是否存活
Thread t = new Thread() {
    @Override
    public void run() {

        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
};

t.start();

System.out.println("hello");

System.out.println(t.getState());
System.out.println(t.isAlive());
//System.out.println(t.isAlive()+" - "+t.getState());
}

注意,线程是NEW和TERMINATED状态的时候,isAlive方法返回的是false,其他状态的情况都会是true

interrupt方法

该方法可以打断一个线程阻塞的状态。

interrupt方法中调用interrupt0方法,interrupt0是一个私有的本地方法:

private native void interrupt0();

interrupt0方法可以改变线程对象中的一个状态:interrupted status ,这状态就表示当前线程是不是被打断了,true表示被打断,false表示没有打断。

Thread中对interrupt0方法的表示为:Just to set the interrupt flag

sleep在进入阻塞状态之前,会先检查一个当前要阻塞的线程中的interrupted status这个状态值是不是false,如果是false就表示当前还没有其他线程想打断我们的阻塞状态,那么我们这个线程就可以正常进入到阻塞状态了,如果这个interrupted status状态值是true,那么就表示当前已经有其他线程要想打断我们的阻塞状态,那么这个sleep就会立马抛出异常来处于这个打断的请求,并且把interrupted status状态值从true改为false,因为这样下次在调用sleep方法的时候,就可以正常进入阻塞状态了。

同时,可以调用Thread类中的【非静态方法】isInterrupted来返回当前线程的interrupted status的状态值。这个值只有两种情况:true和false
true 表示当前【有】 线程要打断我们的阻塞状态
false表示当前【没有】线程要打断我们的阻塞状态

注意,这个非静态方法,只是返回这个“打断标识”值,并不会对这个值进行操作。

可以调用Thread类中的【静态方法】Thread.isInterrupted来返回当前线程的interrupted status的状态值。这个值只有两种情况:true和false

​ true 表示当前【有】 线程要打断我们的阻塞状态

​ false表示当前【没有】线程要打断我们的阻塞状态

注意,这个非静态方法,只是返回这个“打断标识”值,还会对这个值进行操作。如果是true,那么返回后,这个静态方法会把值修改为false。

此博客很详细:https://blog.youkuaiyun.com/zhuyong7/article/details/80852884

Thread中的三个方法:
//打断线程阻塞状态的方法,其实就是改变“打断标识”
public void interrupt(){}
//返回线程“打断标识”的值,但是不会清除这个值
public boolean isInterrupted(){
    return  isInterrupted(false); 
}
//返回线程“打断标识”的值,但是[会]清除这 个值,把true改为false
public static boolean interrupted(){
    return currentThread().isInterrupted(true);
}
join方法
public final synchronized void join(long millis, int nanos)
    throws InterruptedException {

    if (millis < 0) {
        throw new IllegalArgumentException("timeout value is negative");
    }

    if (nanos < 0 || nanos > 999999) {
        throw new IllegalArgumentException(
            "nanosecond timeout value out of range");
    }

    if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
        millis++;
    }

    join(millis);
}
join对于线程的改变
package com.zzb.day44;

public class ThreadTest3 {
	
	public static void main(String[] args) {
		
		Thread t1 = new Thread() {
			public void run() {
				try {
					Thread.sleep(10000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println("t1执行完,即将死亡");
			}
		};
		Thread t2 = new Thread() {
			public void run() {
				//t2要等待t1的死亡
				try {
					t1.join();
					System.out.println("t1死亡,t2执行");
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				System.out.println("t2执行完,即将死亡");
			}
		};
		t1.start();
		t2.start();
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(t1.getState());
		System.out.println(t2.getState());
	}
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值