线程复习笔记

文章链接:http://www.liuschen.com

内容主要来自《Java多线程编程核心技术》 高洪岩著

1.线程的生命周期

线程是一个动态执行的过程,它也有一个从产生到死亡的过程。

(1)生命周期的五种状态

新建(new Thread)

当创建Thread类的一个实例(对象)时,此线程进入新建状态(未被启动)。
例如:Thread t1=new Thread();

就绪(runnable)

线程已经被启动,正在等待被分配给CPU时间片,也就是说此时线程正在就绪队列中排队等候得到CPU资源。例如:t1.start();

运行(running)

线程获得CPU资源正在执行任务(run()方法),此时除非此线程自动放弃CPU资源或者有优先级更高的线程进入,线程将一直运行到结束。

死亡(dead)

当线程执行完毕或被其它线程杀死,线程就进入死亡状态,这时线程不可能再进入就绪状态等待执行。
自然终止:正常运行run()方法后终止
异常终止:调用stop()方法让一个线程终止运行

堵塞(blocked)

由于某种原因导致正在运行的线程让出CPU并暂停自己的执行,即进入堵塞状态。

正在睡眠:用sleep(long t) 方法可使线程进入睡眠方式。一个睡眠着的线程在指定的时间过去可进入就绪状态。

正在等待:调用wait()方法。(调用motify()方法回到就绪状态)
被另一个线程所阻塞:调用suspend()方法。(调用resume()方法恢复)

2.常用方法

void run() 创建该类的子类时必须实现的方法
void start() 开启线程的方法
static void sleep(long t) 释放CPU的执行权,不释放锁
static void sleep(long millis,int nanos)
final void wait()释放CPU的执行权,释放锁
final void notify()
static void yied()可以对当前线程进行临时暂停(让线程将资源释放出来)
3.(1)结束线程原理:就是让run方法结束。而run方法中通常会定义循环结构,所以只要控制住循环即可
(2)方法—-可以boolean标记的形式完成,只要在某一情况下将标记改变,让循环停止即可让线程结束
(3)public final void join()//让线程加入执行,执行某一线程join方法的线程会被冻结,等待某一线程执行结束,该线程才会恢复到可运行状态

引用出处:http://blog.csdn.net/mayouarebest8621/article/details/6755036

2.方法

currentThread():返回调用代码段的线程信息

isAlive():判断线程是否处于活动状态,start之前调用为false,start之后为true

sleep():指定毫秒数让当前线程休眠

getId():取得线程的唯一标识

suspend():挂起(也是有死锁的隐患,和锁有关,废除)

resume():重新开始执行,(和suspend,因为很容易造成资源独占,导致死锁,废除)

stop():停止(一般线程结束都是在线程中通过流程控制来结束,因为用stop太过暴力,会释放线程所有保有的资源,废除)

setPriority():设置线程的优先级

join(重要):当前线程等待新开的线程结束后再结束,多用于主线程和子线程

子线程.start()
子线程.join()

join(long),延时,内部用wait()释放锁
sleep(long),不释放锁

join方法会阻塞线程,所以一个线程不能同时开启多个线程然后join,这样用非但不能达到目的,反而会使逻辑变的混乱。

3.对象监视器(锁)

方法内变量为线程安全,实例中变量非线程安全(多个线程可能会访问同一个实例中的变量)

synchronized修饰方法,先调用该方法在没执行完时会持有锁,使后调用该方法的线程阻塞,直到前一个线程将锁释放。

synchronized(this)同步代码块,两个线程同时访问一个对象中的同步代码块时,先进入线程释放锁之前,后访问的线程阻塞等待。

synchronized同步方法和synchronized(this)互相阻塞

synchronized(非this对象)互相阻塞,互相阻塞表示的是对象监视器相同,在一个线程持有锁,另一个线程调用具有加锁的代码块时就会等待,wait()方法会释放当前线程的锁,sleep()不会释放锁

static方法加synchronized持有的是class锁,而普通方法加synchronized持有的是对象锁,所以两者不能同步

原子性

原子性就是操作的不可分割性,就和加上同步是一个效果,一个线程对一些变量进行操作,操作没有完成就不能有其他线程操作,否则,回写的值就会出现问题,产生脏数据。

volatile是强制从公共堆栈中取得变量,而不是从线程专有的线程中取得,对它的操作不具备原子性,也就是在不同线程同时写入可能会出错。

原子类如:AtomicInteger,前有前缀Atomic

原子类的操作也不一定是线程安全的,因为之外可能有不安全的操作,要综合考虑。

等待通知

锁对象所属的wait()和notify()方法是等待和唤醒,在同步代码块之中,如果所属同一个锁对象的wait()被多个线程调用,那么调用的线程会释放对象锁,然后进入线程等待池中,等待被唤醒。如果调用notify()会随机唤醒锁对象,多调用几次就能唤醒全部,也可以直接调用notifyAll()

ThreadLocal和InheritableThreadLocal

InheritableThreadLocal继承于前者

#同步锁

Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
lock.lock();

condition.await()
condition.signal()
condition.signalAll()

lock相当于之前的synchronized
condition相当于之前的锁对象,里面有相关的等待唤醒方法。只是功能更强大。可以建立多个来保证等待与唤醒线程的准确切换。

公平锁与非公平锁:传入一个boolean来指定

tryLock()立即返回,可以带延时
lock()获取不到,就使当前线程休眠等待

ReentrantReadWriteLock读写锁

读读共享,写写互斥,读写互斥,写读互斥

#线程组与线程池

线程组是为了方便线程的管理

线程池是为了减少线程创建与销毁的开销

单例模式

饿汉模式:直接建立对象,获取直接返回

懒汉模式:为了解决多线程下问题,需要对对象进行双检查,既防止不同线程多次创建实例,又保证了效率

if(obj!=null){
}else{
	synchronized(){
		if(obj==null)
			obj = new Obj();
	}
}

守护线程

在新建的线程启动前setDaemon(true)即可,在守护线程中新开的线程也是守护线程,守护线程不应访问资源,因为守护线程有中断的危险。当JVM中不存在非守护线程时,就会销毁JVM。

Loading Disqus comments...
Table of Contents