/** * @Author qgfzzzzzz * @Date 2019/8/19 * @Version 1.0 * <p> * 通过继承Thread类创建线程 * </p> */ public class MyThreadOne extends Thread { @Override public void run() { for(int i = 0; i < 100; i++){ System.out.println(Thread.currentThread().getName() + " " + i); } } public static void main(String[] args){ new MyThreadOne().start(); new MyThreadOne().start(); } }
/** * @Author qgfzzzzzz * @Date 2019/8/19 * @Version 1.0 * <p> * 通过实现Runnable接口创建线程 * </p> */ public class MyThreadTwo implements Runnable{ @Override public void run() { for(int i = 0; i < 100; i++){ System.out.println(Thread.currentThread().getName() + " " + i); } } public static void main(String[] args){ MyThreadTwo myThreadTwo = new MyThreadTwo(); Thread th1 = new Thread(myThreadTwo, "thread-1"); Thread th2 = new Thread(myThreadTwo, "thread-2"); th1.start(); th2.start(); } }
import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; /** * @Author qgfzzzzzz * @Date 2019/8/19 * @Version 1.0 * <p> * 通过实现Callable接口创建线程 * * 实现Callable接口 * 1】创建Callable接口的实现类,并实现call()方法,然后创建该实现类的实例 * 2】使用FutureTask类来包装Callable对象,该FutureTask对象封装了Callable对象的call()方法的返回值 * 3】使用FutureTask对象作为Thread对象的target创建并启动线程(因为FutureTask实现了Runnable接口) * 4】调用FutureTask对象的get()方法来获得子线程执行结束后的返回值 * </p> */ public class MyThreadThree implements Callable<Integer> { public static void main(String[] args) { MyThreadThree myThreadThree = new MyThreadThree(); FutureTask<Integer> ft = new FutureTask<>(myThreadThree); FutureTask<Integer> ft1 = new FutureTask<>(myThreadThree); System.out.println(Thread.currentThread().getName() + "===== "); new Thread(ft, "thread-1").start(); new Thread(ft1, "thread-2").start(); try { System.out.println("return thread-1'result :" + ft.get()); System.out.println("return thread-2'result :" + ft1.get()); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } @Override public Integer call() throws Exception { for (int i = 0; i < 10; i++) { System.out.println(Thread.currentThread().getName() + " " + i); } return 20; } }
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * @Author qgfzzzzzz * @Date 2019/8/19 * @Version 1.0 * <p> * Executors执行Runnable任务 * </p> */ public class MyThreadFour implements Runnable { @Override public void run() { System.out.println(Thread.currentThread().getName() + " is called"); } public static void main(String[] args){ ExecutorService executorService = Executors.newCachedThreadPool(); for(int i = 0; i < 5; i++){ executorService.execute(new MyThreadFour()); } executorService.shutdown(); } }
import java.util.ArrayList; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; /** * @Author qgfzzzzzz * @Date 2019/8/19 * @Version 1.0 * <p> * Executors执行Callable任务 * </p> */ public class MyThreadFive { // 业务线程 private class AThread implements Callable<String> { private int id; public AThread(int id){ this.id = id; } @Override public String call() { System.out.println("线程:" + id + " 运行.."); try { Thread.sleep(3000); } catch (Exception e) { e.printStackTrace(); } System.out.println("线程:" + id + " -> 结束."); return "返回的字符串" + id; } } public void ExecutorService() { ExecutorService pool = Executors.newFixedThreadPool(4); ArrayList<Future<String>> futures = new ArrayList<>(); for (int i = 0; i < 10; i++) { AThread t = new AThread(i); // Runnable -> execute() // Callable -> submit() Future<String> f = pool.submit(t); futures.add(f); } System.out.println("....开始获取结果中..."); // Future的get方法在获取结果时候将进入阻塞,阻塞直到Callable中的call返回。 for (Future<String> f : futures) { try { System.out.println(f.get()); } catch (Exception e) { e.printStackTrace(); } } System.out.println(".....结束得到结果...."); pool.shutdown(); } public static void main(String[] args) { new MyThreadFive().ExecutorService(); } }
一、继承Thread类创建线程类
(1)定义Thread类的子类,并重写该类的run方法,该run方法的方法体就代表了线程要完成的任务。因此把run()方法称为执行体。
(2)创建Thread子类的实例,即创建了线程对象。
二、通过Runnable接口创建线程类
(1)定义runnable接口的实现类,并重写该接口的run()方法,该run()方法的方法体同样是该线程的线程执行体。
(2)创建 Runnable实现类的实例(注意 ,这里声明的是实现类,构造方法也是实现类的构造方法),并依此实例作为Thread构造方法的参数来创建Thread对象,该Thread对象才是真正的线程对象。
三、通过Callable和Future创建线程
(1)创建Callable接口的实现类,并实现call()方法,该call()方法将作为线程执行体,并且有返回值。
(2)创建Callable实现类的实例(注意 ,这里声明的是实现类,构造方法也是实现类的构造方法),并依此实例作为FutureTask构造方法的参数来创建FutureTask对象,同时该FutureTask对象封装了该Callable对象的call()方法的返回值。
(5)调用FutureTask对象的get()方法来获得子线程执行结束后的返回值
Thread的常用方法:
1.start():启动线程并执行相应的run()方法
2.run():子线程要执行的代码放入run()方法中
3.currentThread():静态的,调取当前的线程
4.getName():获取此线程的名字
5.setName():设置此线程的名字
6.yield():调用此方法的线程释放当前CPU的执行权(很可能自己再次抢到资源)
7.join():在A线程中调用B线程的join()方法,表示:当执行到此方法,A线程停止执行,直至B线程执行完毕,A线程再接着join()之后的代码执行
8.isAlive():判断当前线程是否还存活
9.sleep(long l):显式的让当前线程睡眠l毫秒 (只能捕获异常,因为父类run方法没有抛异常)
10.线程通信(方法在Object类中):wait() notify() notifyAll()
11.getPriority():返回线程优先值
12.setPriority(int newPriority):改变线程的优先级
一、 一、继承Thread类创建线程类
(1)定义Thread类的子类,重写该类run( )方法,方法体为要执行任务
(2)创建Thread子类的实例,即创建线程对象
(3)调用线程对象的start方法启动线程【new 子类名().start();】
二、 通过Runnable接口创建线程类
(1)定义Runnable的实现类(RunnableThreadTest)实现Runnable接口,复写Runnable中的run方法,方法体为线程执行体
(2)创建一个Runnable实现类对象, 为线程对象提供入口方法,以实现类对象构造一个线程类Thread的实例对象,该对象才是真正的线程对象
RunnableThreadTest rtt=new RunnableThreadTest( );
Thread t=new Thread(rtt);// 真正的线程对象
(3)调用真正线程对象的start()方法启动该线程
三、 通过Callable和Future创建线程
(1)创建Callable接口的实现类CallableThreadTest,实现call( )方法,call( )存在返回值:eg:Integer,该call( )将作为线程执行体。
(2)创建CallableThreadTest的实例,创建FutureTask对象封装该实现类对象的call( )的返回值类型
CallableThreadTest ctt=new CallableThreadTest( );
FutureTask<Integer> ft=new FutureTask<>(ctt);
(3)使用FutureTask对象ft作为Thread对象的target,调用.start( )启动新线程
(4)调用FutureTask对象的的get()获取子线程执行结束后的返回值。
使用继承Thread类的方式创建多线程
优势:编写简单,如果访问当前线程,直接使用this即可获得当前线程
劣势:已经继承了Thread类,所以不能够再继承其他父类
采取实现Runnable、Callable接口的方式创建多线程
优势:线程类只实现了Runnable接口和Callable接口,还可以继承其它类,在此情形下多线程可共享同一个target对象,非常适合多个相同线程处理同一份资源的情况,从而将CPU、代码和数据分开,形成清晰的模型,较好的体现了面向对象的思想。
劣势:编程简单,如果需要访问当前线程,必须使用Thread.currentThread( )方法。
1.继承thread类重写run方法
2.实现runnable接口,实现run方法
3.实现callable接口,实现call方法
4.executor框架的最大优点是把任务的提交和执行解耦。要执行任务的人只需把Task描述清楚,然后提交即可。这个Task是怎么被执行的,被谁执行的,什么时候执行的,提交的人就不用关心了。具体点讲,提交一个Callable对象给ExecutorService(如最常用的线程池ThreadPoolExecutor),将得到一个Future对象,调用Future对象的get方法等待执行结果就好了。
经过这样的封装,对于使用者来说,提交任务获取结果的过程大大简化,调用者直接从提交的地方就可以等待获取执行结果。而封装最大的效果是使得真正执行任务的线程们变得不为人知。有没有觉得这个场景似曾相识?我们工作中当老大的老大(且称作LD^2)把一个任务交给我们老大(LD)的时候,到底是LD自己干,还是转过身来拉来一帮苦逼的兄弟加班加点干,那LD^2是不管的。LD^2只用把人描述清楚提及给LD,然后喝着咖啡等着收LD的report即可。等LD一封邮件非常优雅地报告LD^2report结果时,实际操作中是码农A和码农B干了一个月,还是码农ABCDE加班干了一个礼拜,大多是不用体现的。这套机制的优点就是LD^2找个合适的LD出来提交任务即可,接口友好有效,不用为具体怎么干费神费力。
二、 一个最简单的例子
看上去这个执行过程是这个样子。调用这段代码的是老大的老大了,他所需要干的所有事情就是找到一个合适的老大(如下面例子中laodaA就荣幸地被选中了),提交任务就好了。
// 一个有7个作业线程的线程池,老大的老大找到一个管7个人的小团队的老大
ExecutorService laodaA = Executors.newFixedThreadPool(7);
//提交作业给老大,作业内容封装在Callable中,约定好了输出的类型是String。
String outputs = laoda.submit(
new Callable<String>() {
public String call() throws Exception
{
return "I am a task, which submited by the so called laoda, and run by those anonymous workers";
}
//提交后就等着结果吧,到底是手下7个作业中谁领到任务了,老大是不关心的。
}).get();
System.out.println(outputs);
使用上非常简单,其实只有两行语句来完成所有功能:创建一个线程池,提交任务并等待获取执行结果。
例子中生成线程池采用了工具类Executors的静态方法。除了newFixedThreadPool可以生成固定大小的线程池,newCachedThreadPool可以生成一个***、可以自动回收的线程池,newSingleThreadScheduledExecutor可以生成一个单个线程的线程池。newScheduledThreadPool还可以生成支持周期任务的线程池。一般用户场景下各种不同设置要求的线程池都可以这样生成,不用自己new一个线程池出来。
①继承Thread类(真正意义上的线程类),是Runnable接口的实现。
②实现Runnable接口,并重写里面的run方法。
③使用Executor框架创建线程池。Executor框架是juc里提供的线程池的实现。
调用线程的start():启动此线程;调用相应的run()方法
继承于Thread类的线程类,可以直接调用start方法启动线程(使用static也可以实现资源共享).一个线程(对象)只能够执行一次start(),而且不能通过Thread实现类对象的run()去启动一个线程。
实现Runnable接口的类需要再次用Thread类包装后才能调用start方法。(三个Thread对象包装一个类对象,就实现了资源共享)。
线程的使用的话,注意锁和同步的使用。(多线程访问共享资源容易出现线程安全问题)
一般情况下,常见的是第二种。
* Runnable接口有如下好处:
*①避免点继承的局限,一个类可以继承多个接口。
*②适合于资源的共享
/*
* Thread的常用方法:
* 1.start():启动线程并执行相应的run()方法
* 2.run():子线程要执行的代码放入run()方法中
* 3.currentThread():静态的,调取当前的线程
* 4.getName():获取此线程的名字
* 5.setName():设置此线程的名字
* 6.yield():调用此方法的线程释放当前CPU的执行权(很可能自己再次抢到资源)
* 7.join():在A线程中调用B线程的join()方法,表示:当执行到此方法,A线程停止执行,直至B线程执行完毕,
* A线程再接着join()之后的代码执行
* 8.isAlive():判断当前线程是否还存活
* 9.sleep(long l):显式的让当前线程睡眠l毫秒 (只能捕获异常,因为父类run方法没有抛异常)
* 10.线程通信(方法在Object类中):wait() notify() notifyAll()
*
*设置线程的优先级(非绝对,只是相对几率大些)
* getPriority():返回线程优先值
* setPriority(int newPriority):改变线程的优先级
*/