线程
1、Java采用比较传统的方式,在顺序语言的基础上提供对线程的支持:多线程机制是在由执行程序所表示的单一进程中创建任务;
2、Java的线程机制是抢占式,即调度周期会周期性地中断线程,将上下文切换到另一个线程,从而为每一个线程提供时间片,使得每一个线程都会分配到数量合理的时间去驱动它的任务;
3、线程(Thread):一个任务从头到尾的执行流;
4、时间共享(time sharing):单处理器系统中,多个线程共享CPU时间;
5、当程序作为一个应用程序执行,java解释器为main方法启动一个线程;
当程序作为一个Applet执行时,Web浏览器会自动启动一个线程运行applet;
6、线程的状态:新建(new),就绪(Runnable),运行(Run),阻塞(Blocked),结束(Dead):
基本的线程机制
1、 创建线程的基本步骤:①创建Runnable任务类,并实现run方法;
②创建Thread线程类,在主程中用该任务类的实例创建一个线程类Thread,并对其进行操作;
class DemoTask implements Runnable{
public run(){
statements;
//线程暂停的2种常用方式
Thread.sleep(1000); // 或 TimeUnit.MILLISECONDS.sleep(1000);使本线程休眠的便捷方法;
Thread.yield();
};
}
* void main(){
* Thread thread = new Thread(new DemoTask());
* thread.start();
* }※一般不会使用以上的方式直接运行线程,而是使用Executor线程池的方式管理线程,主要的优点有:
①Executor拥有更好地性能;
②Executor能更多地管理线程的行为;
2、Thread线程类

1) Thread.sleep(millis):使线程暂停millis后,回到可执行状态 // 便捷方法TimeUnit.MILLISECONDS.sleep(1000);
Thread.yield():使线程提前结束CPU为其分配的时间片,在下一个时间片线程恢复到可执行状态;
2)join、sleep方法会引起一个必检的异常:InterruptedException;
线程的join、sleep可以使用interrupt()方法打断;
3)线程优先度常量:MIN_PRIORITY(0), NORM_PROORITY(5,主程优先度), MAX_PRIORITY(10);
3、Executor 线程池管理器

1)线程池在Java SE5被引入,使用Java.util.concurrent包中的执行器(Executor)可以对Thread对象进行管理,Executor在客户端和任务执行之间提供了一个间接层,Executor在SE5/SE6时启动任务的优选方式;
2)使用线程池基本步骤:①创建线程池;
②将任务类加入到线程池;
③对线程池加入任务类后的状态进行操作;
import java.util.concurrent.*;
void main() {
ExecutorService executor = Executors.newFixedThreadPool(n); /newCachedThreadPool();
executor.execute(new Task());
executor.shutdown(); /shutdownNow();
//shutdown()能防止新任务被提交给改Executor,当前线程将继续运行在shutdown之前提交的所有任务;3)线程池的类别:
①newCachedThreadPool :创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程;
ExecutorService executor = Executors.newFixedThreadPool();
int size = new Random().nextInt(100);
for(i = 0;i<size;i++)
executor.exetutor(new Runnable());
②newFixedThreadPool :创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待;
ExecutorService executor = Executors.newFixThreadPool(5);
for(int i=0;i<10;i++)
executor.execute(new Runnable());
//此时有5个任务类被阻塞,直到executor内的线程执行完毕空出位置;
③newSingleThreadExecutor :创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行;
ExecutorService executor = Executors.newSingleThreadPool();
//相当于newFixedThreadexecutor(1);
④newScheduledThreadPool :创建一个定长线程池,支持定时及周期性任务执行。延迟执行示例代码如下:
ScheduledExecutorService executor = Executors.newSchrduledThreadPool(5);
executor.schedule(new Runnable() , 1,TimeUnit.SECONDS);
////该线程延迟1秒后执行;
executor.scheduleAtFixedRate(new Runnable(),1,3,TimeUnit.SECONDS);
//该线程延迟1秒后,每3秒执行一次;
4、Callable返回任务类
Runnable是执行工作的独立任务,但是它不返回任何值,如果希望任务在完成时能够返回一个值,可以实现Callable接口取代Runnable接口,同时实现call()方法;
calss DemoTask implements Callable<Date>{
public Date call(){
return new Date();
}
}
main(){
ExecutorServices exetuor = Executors.newCashedThreadPool();
List<Future<Date>> results = ArrsyList<Future<Date>>();
for(int i=0;i<10;i++)
results.add(executor.submit(new DemoTask()));
//使用submit方法会产生Future对象,可以使用isDone()来检测Future是否已经完成,使用get()获取具体值;
for(Future<Date> fs : results){
try{
System.out.println(fs.get());
}catch(InterruptedExcecption e){
}catch(ExecutionException e){
}fianlly{
executor.shutdown();
}
}
}5、优先级
1)线程的优先级将线程的重要性传递给调度器,调度器将更加倾向于让优先权较高的线程先执行(但不是优先权较低的线程得不到执行,只不过被执行的频率比较低);
2)在绝大多数时间里,所有线程都应该以默认的优先级运行;
3)线程优先度常量:MIN_PRIORITY(0), NORM_PROORITY(5,主程优先度), MAX_PRIORITY(10);
class Task implements Runnable{
public void run(){
Thread.currentThread().setPriority(MIN_PRIORITY);
}
}6、后台线程
1)后台(daemon)线程:程序在运行时在后台提供一种通用服务的线程,并且该线程不属于程序中不可或缺的部分;
2)但所有非后台线程结束时,程序也就终止,同时会杀死所有后台线程;反过来说,只要有任何非后台线程还在运行,线程就不会终止;
class DaemonTask implements Runnable{
public void run(){
statements;
//Thread.currentThread().setDaemon(true); 直接在任务类中标注
}
}
main(){
Thread daemon = new Thread(new DaemonTask());
daemon.setDaemon(true);
daemon.start();
}7、直接继承Thread创建线程
class DemoThread extends Thread{
public DemoThread(){
super("testdemo");
start();
}
public void run(){
statements;
}
public static void main(){
new DemoThread();
}
}8.volatile关键字
volatile关键字:被设计用来修饰被不同线程访问和修改的变量,防止编译器对其进行优化操作,如:
int num = 0;
num = 1;
num = 2;
num = 3;
以上编译器会优化为int num = 3 一条语句,这对多线程是很不利的;
可以通过使用volatile修饰num,使编译器放弃优化,全部执行4个动作;
int volatile num = 0;
9.多线程下的异常捕获
1)由于线程的本质特性,是无法捕获从线程中逃逸的异常的,一旦异常逃出任务的run方法,它就会向外传播到控制台;
在java SE5中,可以使用Executor捕获这些异常,而在这之前,只能使用线程组来实现;
2)Thread.UnchaughtExceptionHandler是java SE5中的新接口,允许在每一个Thread对象上都覆着一个异常处理器,UnchaughtExceptionHandler会在线程在因未被捕获的异常而临近死亡时被调用;
3)使用线程池捕获线程异常实例代码
//定义抛出异常线程类
class TaskDemo implements Runnable{
public void run(){
throw new RunTimeException();
}
}
//定义线程异常处理器
class UncaughtExceptionHandlerDemo implements Thread.UncaughtExceptionHandler{
public void uncaughtException(Thread t,Throwable e){
System.out.println("caught"+e);
}
}
方式1.使用默认未捕获异常处理器
public static void main(String[] args){
Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionDemo());
ExecutorService exec = Executors.newCachedThreadPool();
exec.execute(new TaskDemo());
}
方式2.使用自定义未捕获异常处理器
class HandlerFactory implements ThreadFactory{
//自动创建线程,同时绑定未捕获异常处理器,可以在代码块里添加自定义的处理语句;
public Thread newThread(Runnable r){
Thread t = new Thread(r);
t.setUncaughtExceptionHandler(new UncaughtExceptionHandlerDemo());
//System.out.println("eh"=t.getUncaughtexceptionHandler());
return t;
}
}
public static void main(String[] args){
ExecutorService executor = Executors.newCachedThreadPool(new HandlerFactory());
executor.execute(new ThreadDemo());
}

本文详细介绍了Java多线程机制的基础概念与实现方法,包括线程创建、线程池管理、线程优先级设置等内容,并提供了丰富的示例代码。
6万+

被折叠的 条评论
为什么被折叠?



