今天主要是跟大家一起复习一下java当中的线程,同时对于自己来说也是一种巩固。
废话不多说了,立马进入Thread豪华之旅:
一、主要方法:
Start:启动一个线程(线程创建就不用罗嗦了吧,可以通过Thread和Runnable来初始化一个线程对象);
Sleep:将线程睡眠停滞一段时间,单位是毫秒(不释放同步锁,也就是说,睡眠完毕后会继续往下执行);
Wait:将线程设为等待状态,通过Object.wait来调用(释放同步锁,允许其他线程获得锁);
Join:让某个线程执行完毕后才返回(当前线程进入阻塞状态,知道调用join方法的线程执行完毕),可以参考博文:
http://www.blogjava.net/jnbzwm/articles/330549.html;
Interrupt: 中断某个线程(可以使处于sleep/wait/join状态的线程恢复过来),可以参考博文:http://hi.baidu.com/%D6%D0%B9%A4%D0%A1%D0%DC/blog/item/ba854f02c1181c693912bba8.html;
Notify/notifyAll: 唤醒处于wait状态的线程;
Yield: 出让线程的运行权利,让其他线程获得执行机会;
setDaemon: 设置线程为守护线程;
二、状态变迁:
三、常用方法深度解析:
Sleep: 有时候我们在开发中需要让某个即将运行或者正在运行的thread休息一段时间(比如当前正在进行文件流的读取操作,当我们调用一个对文件记录写入数据库的线程时,此时文件还未读完或者cpu还很高,就可以让这个线程先睡个觉,呆会让它尽情去执行),调用方法非常简单:Thread.sleep(2000);这就是让线程睡2秒钟的觉,睡觉完后它会继续往下走;
Wait: 在生产者/消费者模型中wait就表现得淋漓尽致,注意一点:wait() 必须在synchronized 函数或者代码块里面;执行wait后,当前线程处于等待阻塞状态,需要通过notify/notifyall来唤醒,唤醒后之前处于wait状态的线程不会立即执行,而是需要重新竞争同步锁,只有获取到锁后才会进入到运行等待队列中;它跟sleep的区别在于:
setDaemon: 通过一个例子可以清晰地看出该方法的效果:
public class TestThread extends Thread { public void run(){ for(int i = 1; i <= 100; i++){ try{ Thread.sleep(100); } catch (InterruptedException ex){ ex.printStackTrace(); } System.out.println(i); } } public static void main(String [] args){ TestThread test = new TestThread(); // 如果不设置daemon,那么线程将输出100后才结束 test.setDaemon(true); test.start(); System.out.println("isDaemon = " + test.isDaemon()); try { System.in.read(); // 接受输入,使程序在此停顿,一旦接收到用户输入,main线程结束,守护线程自动结束 } catch (IOException ex) { ex.printStackTrace(); } } }
通过这个实例可以看出:守护线程的优先级是较低的(相对于一般的用户线程(默认就是setDaemon(false))),当main主线程结束后,守护线程不管有没有运行完毕都立马结束,所以它的生命周期是跟main绑定在一起的,而一般的线程它跟main之间是并行的关系,即使main结束了,用户线程还是会继续运行;
四、实际开发中运用:
实际开发中,我很少直接调用new Thread(XXX).start来执行一个线程程序,除非这个线程是比较简单的,比如只是对数据库中某张表进行扫描;但是当我们需要去进行复杂处理的时候就需要用到线程池了,目前线程池也有一些现成的框架和工具,大家有兴趣的话可以去网上搜罗一下,我用的比较多的是java.util.concurrent包中的Executors类,通过它可以对线程队列中的线程进行调度管理,算是比较方便和好用的了,下面我就简单说说它的具体用法:
public class ThreadService { private ScheduledExecutorService executorService = null; private ScheduledThreadPoolExecutor scheduledThreadPoolExecutor =null; public ThreadService(){ int cpu = Runtime.getRuntime().availableProcessors(); int corePoolSize = 2*cpu + 1; if (executorService == null){ executorService = Executors.newScheduledThreadPool(corePoolSize); } if(scheduledThreadPoolExecutor == null){ scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(corePoolSize); } } public ScheduledExecutorService getExecutorService() { return executorService; } public ScheduledThreadPoolExecutor getScheduledThreadPoolExecutor(){ return scheduledThreadPoolExecutor; } }
Public class TestThread implements Runnable{
Private String name; Public void init(String name){ //该方法不是必须的,它可以传递一些参数 this.name = name; } Public void run(){ //在这里进行具体的任务操作 Sysout(name); } }
ThreadService ser = new ThreadService(); TestThread test = new Thread(new TestThread()); test.init(“我是江上明月”); ser. getExecutorService().execute(test);
这样就可以将一个线程放入到线程池中了,当然还可以继续放入多个线程,放完之后我们就不用操心了,线程池有自己的调度程序去运行各个线程任务。