java线程概述

Posted 空方块

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java线程概述相关的知识,希望对你有一定的参考价值。

1.线程概述

#1:Main函数本身就是一个线程,主线程。

#2:多线程可以继承Thread类,也可以继承Runnable接口。

#3:没有严格意义上的并发。对于单核CPU的物理机来说,同一时刻有且只有一条线程在执行,运行多条线程,只是CPU在切换执行权而已,切换速度取决于CPU主频。

#4:JVM自身有很多后台线程执行。

#5:Runnable是一个可执行任务的标志,Thread是线程所有API的体现。

#6:thread可以显式访问heap中的共享对象,每个线程都留有自用的局部变量空间。

2.线程的状态

#1线程的初始化:实例化Thread的一个子类。

#2线程的运行状态:显式调用start方法,但是并不是调用的瞬间,CPU立即运行,还需要等待CPU的轮询,获取CPU的执行权。

#3线程的冻结状态:调用sleep或者wait方法后,会放弃CPU的执行权,处于冻结。出现异常或者中断都会直接死亡。

#4线程的死亡状态:正常执行逻辑完毕,线程会正常死亡,死亡线程不会跳到其他状态。

3.线程的创建与管理

3.1.线程创建

public Thread(ThreadGroup group, Runnable target, String name,long stackSize);

Thread name:线程名称,默认Thread-N,N是个唯一的数字。
Runnable target:runnable是thread要执行的指令列表。Thread class本身实现了Runnable interface。
Thread group:默认情况下,thread会被分配给与调用constructor的thread一样的thread group。
Stack size:每一个thread都有一个给method运行时保存临时变量的stack。极度不建议在可一致性程序中使用stack size。

3.2.线程的生命周期

 public class Thread implements Runnable
  		public  void start();
  		public  void run();
 		public  void stop();// 停止,已废除,勿使用
 		public  void resume();//恢复,已废除,勿使用
 		public  void suspend();//暂停,已废除,勿使用
 		public  static void sleep(long millis);
	 	public  static void sleep(long millis , int nanos);
 		public  boolean isAlive();
 		public  void interrupt();
 	 	public  boolean isInterrupted();
		public  static boolean isInterrupted();
 		public  void join() throws InterruptedException;

3.2.1.创建线程

thread是由Thread class的instance来表示,所以创建thread是通过该class的constructor来完成。

3.2.2.启动线程

在start()方法被调用后,新的thread是"活跃的"。如果isAlive()返回true,则该thread已经被启动并正在运行run()这个method,如果isAlive()返回false,则该thread可能还没有启动或者已经被终结。

3.2.3.线程的终结

终结Thread的唯一办法就是安排run()方法完成。
run()这个method不能抛出checked异常,单如同其他的Java method,它可以抛出unchecked异常(一个被extends的RuntimeExceptionclass的异常),或者没有catch到由run()方法所调用的某些功能所抛出的运行是异常,同样也会造成thread的停止。

3.2.4.线程的暂停、挂起、恢复

thread是可以通过sleep()方法來掛起自己的执行动作一段指定的期间。

3.2.5.线程的善后

只要其他线程运行中的对象该持有对已经终结的thread对象的引用,其他的thread就能够运行已终结的thread的method并去除那些信息。
如果代表已终结thread的对象超出生命周期的scope,则该thread对象就会被garbage collected。
join()方法会被block住直到thread完成他的run()方法。如果run()方法完成,join()方法就会立即返回。

3.2.6.俩种停止线程的方式

#1:设定标记

private volatile boolean done = false;
while (!done) 
...
#2:中断Thread

interrupt()方法来中断任何blocking method。
interrupt()对中断的线程的有俩个效应:
1>会导致任何blocked method抛出InterruptedException。
2>设定thread对象内部的标记来指示此thread已经被中断,可使用isInterrupted()方法来查询这个标记,此method会在thread已经被中断时返回true

Note: 如果一个线程处于了阻塞状态(如:线程调用了thread.sleep()、thread.join()、thread.wait()、JDK1.5中的condition.await()、以及可中断的通道上的I/O操作方法后可进入阻塞状态),
 则在线程在检查中断标识时如果发现中断标示为true,则会在这些阻塞方法如:sleep、join、wait、JDK1.5中的condition.await及可中断的通道上的 I/O操作方法)调用处抛出InterruptedException异常
  ,并且在抛出异常后立即将线程的中断标别位清除,即重新设置为false.抛出异常是为了线程从阻塞状态醒过来,并在结束线程前让程序员有足够的时间来处理中断请求.

3.2.7.等待与通知

void wait():等待条件发生。必须在synchronized method或块中调用。<br>
void wait(long timeout):等待条件发生。必须在synchronized method或块中调用。timeout返回<br>
void wait(long timeout , int nanos):等待条件发生。必须在synchronized method或块中调用。timeout返回
void notify():通知任意单一正在等待的thread此条件已经发生。必须在synchronized method或块中调用。
void notifyAll():通知正在所有等待的thread条件已经发生。必须在synchronized method或块中调用。


#1:等待、通知机制不能够解决synchronized机制能够解决的race condition问题。

#2:synchronized代码块里,sleep()方法和wait()方法之间的差异:

wait()方法执行的时候,同步lock会被释放(virtual machine本身于内部执行),在收到通知时,thread在wait()方法返回前重新取得此同步锁sleep()方法则一直持有锁

#3:notify()方法在没有其他线程在等待的时候被调用到,就只是返回且通知也被遗失掉。

4. Thread与对象

在Java中,Thread的instance也只是一个对象:它可以被传递给method,且任何持有对其他thread引用的thread可以执行其他thread对象的method。

Thread对象并不是thread的“本身”,它只是用来代替一组关于thread的method与数据的封装信息,而这些method与数据可被其他thread所访问。

Note:

#1:当前Thread对象:Thread.currentThread()

5.线程安全

当多个线程访问同一个资源时,不需要考虑运行环境的时序调度和交替执行,并不需要额外的同步协调,这个资源仍然是正确的,则认为是线程安全的。线程安全的类封装了任何必要的同步,因此客户不需要自己提供。

#1:无状态的对象永远是线程安全的。如:Servlet。

#2:原子类。java.util.concurrent.atomic包。

#3:锁。

#3.1.为了保证状态的一致性,必须在单一的原子操作中更新相互关联的状态变量。

#3.2.决定同步块的大小,权衡:安全性(不能妥协)、简单性和性能。

#3.3.耗时操作期间不要占用锁,如:网路或控制台IO。

#3.4.同一份数据,多个线程访问才需要加锁,加锁时必须使用同一个锁。

3.1.内部锁:synchronized

synchronized(lock)
     // 临界区代码

#1:同一时刻至多存在一条线程占有该监视器,其他线程尝试请求获取该同步块相同的锁时,其他线程处于阻塞或阻塞状态,直到监视器释放。

#2:临界区范围尽量缩小,为了响应性着想。

#3:可重进入。当前线程可重复请求已经占用的synchronized锁。冲进入的实现关联一个请求计数器和占有线程,重进入时,计数递增。

#4:同步方法使用this锁,静态同步方法使用static锁。

6.Thread Group

所有thread都是属于某一个thread group,thread group是定义在java.lang.ThreadGroup这个Class中。
thread不只是随意地把thread组织起来,它们是互相关联的。
每个thread group是有层次结构树的。

每个java程序默认有俩个thread group:
1>带有某些系统层任务的thread的system thread group
2>main thread group
 
没有指定线程组,会发生
1>如果安装过安全管理器,安全管理器的getThreadGroup()方法被调用且该thread会加入由该method所返回的group。
2>否则,该thread会加入当前的thread group。

优点:
1>能够对group中所有thread操作。如interrupt()
2>thread的security有关。保证数据只能被某个线程去操作。

7.Thread 与 Java安全性

默认设置中,当thread或thread group尝试特定操作时,由java.lang.SecurityManager这个class实例安全管理器来判断是否是允许被操作。System.setSecurityManager(new T extends SecurityManager());

public void checkAccess(Thread t)//检测当前的线程是否被允许修改thread t的状态
public void checkAccess(ThreadGroup g)//检测当前的线程是否被允许修改group g的状态
    public void checkAccess(Thread t) 
        if (t == null) 
            throw new NullPointerException("thread can't be null");
        
        if (t.getThreadGroup() == rootGroup) 
            checkPermission(SecurityConstants.MODIFY_THREAD_PERMISSION);
         else 
            // just return
        
    

8.Daemon Thread

#1:Java有俩种线程:daemon与user。
#2:任何thread都可以是daemon或user的。
#3:daemon与user几乎在每个方面都是相同的,daemon thread是用来服务user thread的。

#4:守护线程的优先度比较低,GC线程是典型的守护线程。

#5:线程通过setDaemon来设置是否是守护线程,start()执行后,就不能通过setDaemon来控制是否是守护线程了。

9.线程调度

#1:线程优先度

可用的优先度最小的是1,最大的是10,默认的值为5,第11个优先度(优先级为0)是保留给VM用的。
Thread.setPriority(int newPriority);可以对线程的优先度进行设置。
一般来说,尝试以优先度来影响调度指挥得到有限的好处,但是这个优先度不能直接影响,优先算法内部实现较复杂。

#2:优先度计算

1>window优先度计算
1.1->thread具有的优先级继承功能
1.2->设计的优先级减去一个表示多久前实际运算过的值。随着时间的进行,这个值趋向于0,主要用于区分优先级相同的thread
1.3->很久没有运行的thread会被暂时地对优先级进行加速
1.4->有键盘鼠标点击的程序中运行的thread优先级会被加速超过其他程序的thread

2>Solaris优先度计算
2.1->thread具有的优先级继承功能
2.2->实际的thread优先级是从0-59,这个值由thread已经运行了多久来决定的。
2.3->Solaris还有各种调度class


以上是关于java线程概述的主要内容,如果未能解决你的问题,请参考以下文章

java多线程基本概述

[C++11 多线程同步] --- 线程同步概述

[C++11 多线程同步] --- 线程同步概述

java.util.concurrent.RejectedExecutionException异常发生的时机

Java多线程案例之线程池

java之StringBuffer类