java多线程

一、线程与进程
几乎所有的操作系统都支持同时运行多个任务,一个任务通常就是一个程序,每个运行中的程序就是一个进程。
当一个程序运行时,内部可能包含了多个顺序执行流,每个顺序执行流就是一个线程。


二、线程的创建及运行
1、线程的创建
继承Thread类
实现Runnable接口
2、运行
调用start()方法。
3、两种方式的对比
  采用实现Runnable接口方式的多线程:
  》线程类只是实现了Runnable接口,还可以继承其他类。
  》在这种方式下,可以多个线程共享同一个target对象,所以非常适合多个相同线程来处理同一份资源的情况,从而可以将CPU、代码和数据分开,
形成清晰的模型,较好地体现了面向对象的思想。
  》劣势为:变成思想复杂,如果需要访问当前线程,必须使用Thread.currentThread()方法。
  采用继承Thread类方式的多线程:
》劣势为:因为线程类已经继承了Thread类,所以不能再继承其他父类。
》优势为:编写简单,如果需要访问当前线程,无需使用Thread.currentThread()方法,直接使用this即可获得当前线程。


三、线程的生命周期
新建(New):当使用关键字New创建了一个线程之后,该线程就处于新建状态。
就绪(Runnable):当线程对象调用了start()方法之后,该线程处于就绪状态。
运行(Running):如果处于就绪状态的线程获得了CPU,开始运行run方法的线程执行体,则该线程处于运行状态。
阻塞(Blocked):运行中的线程遇到特殊情况无法继续执行时,就进入阻塞状态。被阻塞的线程在合适时候重新进入就绪状态,而不是运行状态。
死亡(Dead):run()方法执行完成,线程正常结束。线程抛出一个未捕获的Exception或者Error.直接调用该线程的stop()方法来结束该线程,均能
导致线程死亡。


isAlive():为了测试某条线程是否已经死亡,可以调用线程对象的该方法,当线程处于就绪、运行、阻塞三种状态时,返回true.
当线程处于新建、死亡两种状态时,返回false。


四、控制线程
join():让一个线程等待另外一个线程完成的方法。当在某个程序执行流中调用其他线程的该方法时,调用线程将被阻塞,直到被join()方法加入
的join线程完成为止(被调用join方法的线程先执行)。


后台线程:在后台运行,任务是为其他线程提供服务。调用Thread对象的setDaemon(true)方法可以将指定线程设置成后台线程。
特征:如果所有的前台线程都死亡,后台线程会自动死亡。


sleep():调用该方法后线程进入阻塞状态。休眠时间内,线程不会得到执行的机会,即使系统中没有其他可运行的线程,处于sleep中的线程
也不会运行。


yield():线程让步。它可以让当前正在执行的线程暂停,但它不会阻塞该线程,它只是将该线程转入就绪状态。
yeild只是让当前线程暂停一下,让系统的线程调度器重新调度依次。然后系统根据线程的优先级安排线程运行。完全可能调用该方法后,
该线程重新被运行。


setPriority(int newPriority):设置线程的优先级。
getPriority():返回线程的优先级。




五、线程的同步


java多线程支持引入了同步监视器来解决线程安全问题。
同步代码块:
synchronized(obj){}
同步方法:
synchronized 修饰方法。


任何线程进入同步代码块、同步方法之前,必须先获得对同步监视器的锁定。


下面情况会释放对同步监视器的锁定:
》当前线程的同步方法、同步代码块执行结束,当前线程即释放同步监视器。
》当线程在同步代码块、同步方法中遇到break、return终止了该代码块、该方法的继续执行,当前线程将会释放同步监视器。
》当线程在同步代码块、同步方法中出现了未处理的Error或Exception,导致了该代码块、该同步方法异常结束时,将会释放同步监视器。
》当线程执行同步代码块或同步方法时,程序执行了同步监视器对象的wait()方法,则当前线程暂停,并释放同步监视器。


下面情况不会释放同步监视器:
》线程执行同步代码块或同步方法时,程序调用Thread.sleep()、Thread.yield()方法来暂停当前线程的执行,当前线程不会释放同步监视器。
》线程执行同步代码块时,其他线程调用了该线程的suspend方法将该线程挂起,该线程不会释放同步监视器。


同步锁(Lock)


ReadWriteLock(读写锁)
ReentrantLock(可重入锁)(常用)


private final ReentrantLock lock = new ReentrantLock();
lock.lock();
.....
finally{
 lock.unlock();
}


死锁:当两个线程相互等待对方释放同步监视器时就会发生死锁。


六、线程通信


wait():导致当前线程等待,直到其他线程调用该同步监视器的notify()方法或notifyAll()方法来唤醒该线程。
----》调用wait()方法的当前线程会释放对同步监视器的锁定。


notify():唤醒在此同步监视器上等待的单个线程。选择是任意性的。只有当前线程放弃对同步监视器的锁定后,才可以执行被唤醒的线程。


notifyAll():唤醒在此同步监视器上等待的所有线程。只有当前线程放弃对同步监视器的锁定后,才可以执行被唤醒的线程。


当使用Lock对象来保证同步时,java提供了一个Condition类来保持协调,使用Condition可以让那些已经得到Lock对象却无法继续执行的线程释放
Lock对象,Condition对象也可以唤醒其他处于等待的线程。
await()、signal()、signalAll();


private final Lock lock = new ReentrantLock();
private final Condition cond = lock.newCondition();
cond.await();


使用管道流
管道流有3中存在形式:PipedInputStream和PipedOutputStream,PipedReader和PipedWriter以及Pipe.SinkChannel和Pipe.SourceChannel,
它们分别是管道字节流、管道字符流和新IO的管道Channel.




七、线程组合未处理的异常


java使用ThreadGroup来表示线程组,它可以对一批线程进行分类管理,对线程组的控制相当于同时控制这批线程。用户创建的所有线程都属于指定
线程组,如果程序没有显示指定线程属于哪个线程组,则该线程属于默认线程组。在默认情况下,子线程和创建它的父线程属于同一个线程组。


int activeCount():返回此线程组中活动线程的数目。
interrupt():中断此线程组中的所有线程。
isDaemon():判断该线程组是否是后台线程组。
setDaemon(boolean daemon):把该线程组设置成后台线程组。
setMaxPriority(int pri):设置线程组的最高优先级。




八、Callable和Future(jdk1.5开始有)


创建、并启动有返回值的线程的步骤如下:
1、创建Callable接口的实现类,并实现call()方法,该call()方法将作为线程执行体,且该call方法有返回值。
2、创建Callable实现类的实例,使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值。
3、使用FutureTask对象作为Thread对象的target创建、并启动新线程。
4、调用FutureTask对象的方法来获得子线程执行结束后的返回值。


九、线程池


jdk1.5提供了一个Executors工厂类来生产线程池。


newCachedThreadPool()、newFixedThreadPool(int nThreads)、newSingleThreadExecutor()、newScheduledThreadPool(int corePoolSize)、
newSingleThreadScheduledExecutor()等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值