Java线程的基本机制

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

线程

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());
}





评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值