Threads
线程是指进程中的一个执行流程,一个线程由多个线程组件,即在一个进程中可以执行多个线程。即在一个进程中可以运
行多个线程,当进程内的多个线程同时运行,这种方式称为并发运行。
不同进程之间不能共享代码和数据空间,而同一进程的不同线程可以共享代码和数据空间。
进程和线程的主要区别就是:每个进程都需要操作系统为其分配独立的内存地址空间,而同一进程的所有线程在同一块
地址空间中工作,这些线程可以共享同一块内存和系统资源。
java中的线程。
分为 前台线程 -- 执行线程
后台线程-- 守护线程和精灵线程。
Thread类的 run()方法是专门被自身的线程执行的,主线程不能调用,否则违背了Thread类提供run()方法的初衷。
1 新建状态。(New)
用new语句创建的线程对象处于新建状态。仅仅在堆区分配了内存;
2 就绪状态 (Runable)
当一个线程对象创建后,其他线程调用他的start()方法, 线程进入就绪状态,这个线程位于可运行池中,
等待获得CPU的使用权。
3 运行状态(Running)
这个状态线程占用CPU,执行程序代码,在并发运行环境中,如果,计算机只有一个CPU那么任何时间只有一个线程处
于这个状态,若有多个CPU,那么同一时刻,可以让几个线程占用不同的CPU使他们都处于运行状态,只有处于就绪状态的
线程才有机会,转到运行状态。
4 阻塞状态 (Blocked)
当线程处于阻塞状态时,java虚拟机不会给线程分配CPU,直到线程重新进入就绪状态,才有机会进入运行状态。
分三种
位于对象等待池中的阻塞状态。运行状态执行了某个对象的wait()方法;
位于对象锁池中的阻塞状态:线程处于运行状态,但同步锁被其他线程占用,java虚拟机就会把这个线程放到这个对
象的锁池中,
其他阻塞状态: 当前线程执行了sleep()方法,或者调用其他线程的join()方法,或者发出了I/O请求时,就会进入
这个状态,当一个线程执行System.in.read()方法时,就会发出一个I/O请求,该线程放弃CpU。
5,死亡状态(Dead)
当线程退出run()方法时,就会进入死亡状态。线程正常结束生命状态或是异常结束,都不会对其他线程造成影响。
6 void sleepingThread.interrupt() 中断某个线程的阻塞状态。
7 boolean otherThread.isInterrupted() 测试某个线程是否被中断
8 void join() 挂起当前线程,直至它所调用的线程终止才被运行, 谁调用谁阻塞
9 wait() 执行该方法的线程执行释放对象的锁。java虚拟机把该线程放到该对象的等待池中,该线程等待其它线程将其唤醒。
notify() 从对象的等待池中随机选择一个线程,把它转到对象的锁池中,如果对象的等待池中没有任何线程,那么notify()方法
什么也不做。
wait() notify() notifyAll(),这三个只能写在同步代码块。
线程的死锁: A线程在等待B线程持有的锁。而B线程等待A线程持有的锁。
线程的让步:Thread.yield() 方法,如果此时具有相同优先级的线程处于就绪状态,那么yiled()方法将把当前运行的线程放到
可运行池中使另一个线程的运行,若没有相同优先级的可运行线程,则yield()什么也不做。
sleep()和yield()方法都是Thread类的静态方法。都会使当前运行的线程放弃CPU把运行机会让给别的线程。
sleep()方法不考虑其他线程优先级,
yield()只会给相同优先级或者更高优先级的线程一个运行机会,
sleep()方法转到阻塞状态, yield()方法转到就绪状态。
sleep()方法会抛出InterruptedExcetion,yield()方法不会抛出异常。
sleep()比yield()方法具有更好的可移植性。
yield(),方法唯一用途是测试期间认为提高册程序的并发性能,以帮助发现一些隐藏的错误。 所以并不常用。
10 关于interrupt,isInterrupted,Interrupted三个方法的理解。
interrupt,和isInterrupted,是Thread类中的非静态方法,可以用线程对象来访问。 t.interrupt() t.isInterrupted()
Interrupted是Thread类中的静态方法,可以用类名来访问 Thread.interrupted();
interrupt可以用来中断线程
interrupted isInterrupted 可以用来判断线程是否被中断过。
一个线程A是不可能调用线程B的interrupt方法来中断B线程的运行。
因为线程A调用线程B的interrupt方法的时候,线程A肯定是在使用cup运行这个中断方法的代码,这个线程B肯定
没有在使用CPU运行代码了(同一时刻只可能有一个线程使用CPU在运行代码),所以就谈不上说线程A调用线程B
的interrupt方法把正在运行的线程B给中断了。
一个线程在使用CPU运行时可以自己调用interrupt来中断自己,交出CPU,回到就绪状态。
那就是每一个线程对象中有一个特殊的标记,那就是可以标记出这个线程有没有被其他线程进行尝试中断过。
因为线程A中是可以调用线程B的interrupt方法来尝试中断线程B的,虽然这样的中断并不能起真正的中断作用。
但是可以把线程B对象中的某个标识。从false改为true表示在某个情况下,有其他线程想中断你了。
那么也就是说。我们可以在线程A中通知线程B,我在某个条件满足的情况下,至少尝试着调用你的interrupt方法
去中断你了。然后这个时候线程B在运行的时候,过程中就可以通过另外俩个方法 isInterrupted和interrupted
来知道是否有其他线程在试图中断自己了。然后就是线程B根据这个信息,来决定自己是否要中断自己。或者继续
运行下去。
当在线程B执行的代码中调用Thread.interrupted()方法的时候,会显示出是否有其他线程视图中断自己也就是
线程B,如果显示为true,注意了。这个时候Thread.interrupted()会接着把这个状态信息,从true改为false,
因为线程B可能被另外多个线程多次中断,这个方法就可以让我们把之前的中断信息给抹去,因为有可能线程B里
面根本不想理会之前的中断信息。 isInterrupted是非静态方法。可以用对象来调用,它也能返回ture或者false
来表示线程B,是否有被其他线程尝试中断的情况。但是这里并不会修改这个信息,也就是如果这时候显示为true
。那么之后也会显示为ture,这一点和静态方法 interrupted不一样的,
最后一个问题:
为什么,线程在wait或者sleep期间被中断的时候会抛出InterruptedException呢。
因为处于这些状态的线程是不可能拿到CPU的使用权的。那么意味着即使我调用你的interrupted方法去尝试的通知
“我试图去中断你了“, 那么你也是不可能拿到CPU的使用权去处理的我的这种中断的通知信息的,所以这时候就会
抛出异常了,(当然我们也可以利用这个特点来改变一个阻塞状态线程的状态)