Java多线程并发技术
JAVA多线程实现方式主要有三种:继承Thread类、实现Runnable接口、使用ExecutorService、Callable、Future实现有返回结果的多线程。其中前两种方式线程执行完后都没有返回值,只有最后一种是带返回值的。
1、 继承Thread类实现多线程
public class MyThread extends Thread { public void run() { //重写run方法 System.out.println("MyThread.run()"); } } //调用代码 MyThread myThread1 = new MyThread(); MyThread myThread2 = new MyThread(); myThread1.start(); // 启动线程 myThread2.start();
|
Thread本质上也是实现了Runnable接口的一个实例,它代表一个线程的实例,并且,启动线程的唯一方法就是通过Thread类的start()实例方法
|
2、 实现Runnable接口方式实现多线程
//如果自己的类已经extends另一个类,就无法直接extends Thread,此时,必须实现一个Runnable接口,如下: public class MyThread extends OtherClass implements Runnable { public void run() { System.out.println("MyThread.run()"); } }
|
//为了启动MyThread,需要首先实例化一个Thread,并传入自己的MyThread实例: MyThread myThread = new MyThread(); Thread thread = new Thread(myThread); thread.start();
|
3、 使用ExecutorService、Callable、Future实现有返回结果的多线程
ExecutorService、Callable、Future这个对象实际上都是属于Executor框架中的功能类。可返回值的任务必须实现Callable接口,类似的,无返回值的任务必须Runnable接口。执行Callable任务后,可以获取一个Future的对象,在该对象上调用get就可以获取到Callable任务返回的Object了,再结合线程池接口ExecutorService就可以实现有返回结果的多线程了。
- int taskSize = 5;
- ExecutorService pool = Executors.newFixedThreadPool(taskSize); // 创建一个线程池
- // 创建多个有返回值的任务
- List<Future> list = new ArrayList<Future>();
- for (int i = 0; i < taskSize; i++) {
- Callable c = new MyCallable(i + " ");
- Future f = pool.submit(c); // 执行任务并获取Future对象
- list.add(f);
- }
- pool.shutdown(); // 关闭线程池
- for (Future f : list) {
- // 从Future对象上获取任务的返回值,并输出到控制台
- System.out.println(">>>" + f.get().toString()); //get()是阻塞调用
- }
// 实现Callable接口 - class MyCallable implements Callable<Object> {
- private String taskNum;
- MyCallable(String taskNum) {
- this.taskNum = taskNum;
- }
- public Object call() throws Exception {
- Thread.sleep(1000);
- return taskNum + "任务返回运行结果,当前任务时间【" + time + "毫秒】";
- }
- }
|
4、 Executors类说明:
参考文献:http://www.iteye.com/topic/366591
Executors类,提供了一系列工厂方法用于创建线程池,返回的线程池都实现了ExecutorService接口。
public static ExecutorService newFixedThreadPool(int nThreads)
创建固定数目线程的线程池。
public static ExecutorService newCachedThreadPool()
创建一个可缓存的线程池,调用execute 将重用以前构造的线程(如果线程可用)。如果现有线程没有可用的,则创建一个新线程并添加到池中。终止并从缓存中移除那些已有 60 秒钟未被使用的线程。
public static ExecutorService newSingleThreadExecutor()
创建一个单线程化的Executor。
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
创建一个支持定时及周期性的任务执行的线程池,多数情况下可用来替代Timer类。
ExecutoreService提供了submit()方法,传递一个Callable,或Runnable,返回Future。如果Executor后台线程池还没有完成Callable的计算,这调用返回Future对象的get()方法,会阻塞直到计算完成。
5、 其他获得线程执行结果的方式:
javascript:void(0)
基于FutureTask;
在上述实现中,任务callable被提交后返回一个future用于获得执行结果;
FutureTask实现了两个接口,Runnable和Future,所以它既可以作为Runnable被线程执行,又可以作为Future得到Callable的返回值;
- public class CallableAndFuture {
- public static void main(String[] args) {
- Callable<Integer> callable = new Callable<Integer>() {
- public Integer call() throws Exception {
- return new Random().nextInt(100);
- }
- };
- FutureTask<Integer> future = new FutureTask<Integer>(callable);
- new Thread(future).start();
- try {
- Thread.sleep(5000);// 可能做一些事情
- System.out.println(future.get());
- } catch (InterruptedException e) {
- e.printStackTrace();
- } catch (ExecutionException e) {
- e.printStackTrace();
- }
- }
19. }
|
基于CompletionService的实现方式
- public class CallableAndFuture {
- public static void main(String[] args) {
- ExecutorService threadPool = Executors.newCachedThreadPool();
- CompletionService<Integer> cs = new ExecutorCompletionService<Integer>(threadPool);
- for(int i = 1; i < 5; i++) {
- final int taskID = i;
- cs.submit(new Callable<Integer>() {
- public Integer call() throws Exception {
- return taskID;
- }
- });
- }
- // 可能做一些事情
- for(int i = 1; i < 5; i++) {
- try {
//take 每次获得一个执行完成的future,如果没有就阻塞,与其功能相同的非阻塞调用时poll - System.out.println(cs.take().get());
- } catch (InterruptedException e) {
- e.printStackTrace();
- } catch (ExecutionException e) {
- e.printStackTrace();
- }
- }
- }
}
|
6、 多线程相关函数:
参考文献:javascript:void(0)
线程中断:javascript:void(0)
void
| interrupt() // 中断线程。其实只是设置了中断标志位 |
static boolean
| interrupted() // 测试调用该方法的当前线程是否已经中断。同时清除中断标志位 |
boolean
| isInterrupted() // 测试this线程是否已经中断。不清除中断标志位 |
线程让步
static void
| yield() // 暂停当前正在执行的线程对象,并执行其他线程 |
注意: 如果存在synchronized线程同步的话,线程让步不会释放锁(监视器对象)。
线程休眠:
static void
| sleep(long millis)// 在指定的毫秒数内让当前正在执行的线程休眠(暂停执行)。 |
注意: 如果存在synchronized线程同步的话,线程休眠不会释放锁(监视器对象),但会释放cpu;
线程合并:http://uule.iteye.com/blog/1101994
void
| join() 等待该线程终止。 |
void
| join(long millis) 等待该线程终止的时间最长为 millis 毫秒。 |
void
| join(long millis, int nanos) 等待该线程终止的时间最长为 millis 毫秒 + nanos 纳秒。 |
线程合并是优先执行调用该方法的线程,再执行当前线程。内部是用wait方法实现的
- public class JoinTest {
- public static void main(String[] args) throws InterruptedException {
- JoinThread t1 = new JoinThread("t1");
- JoinThread t2 = new JoinThread("t2");
- t1.start(); //启动线程
- t2.start(); //启动线程
- t1.join(); //等待该线程执行完毕
- t2.join(); //
- System.out.println("主线程开始执行!");
- }
11. } class JoinThread extends Thread { - public JoinThread(String name) {
- super(name);
- }
- public void run() {
- for(int i = 1; i <= 10; i++)
- System.out.println(getName() + getId() + "执行了" + i + "次");
- }
}
|
7、 线程同步之锁