1、创建线程的三种方式
1.1创建线程方式一(不推荐:由于java的单继承性):继承Thread类,并重写run方法,调用start开启线程
//创建线程的方法一:继承Thread类,并重写run方法,调用start开启线程
//线程开启(start)不一定立即执行,由cpu调度执行
public class MyFirshThread extends Thread{
@Override
public void run() {
//run方法体
for (int i = 0; i < 20 ; i++) {
System.out.println("看代码"+i);
}
}
public static void main(String[] args) {
//main方法 主线程
//创建一个线程对象
MyFirshThread myFirshThread = new MyFirshThread();
//调用start()方法启动线程
myFirshThread.start();
for (int i = 0; i < 2000; i++) {
System.out.println("学习++"+i);
}
}
}
执行结果:主程序和创建的线程是交叉运行的,也就是并行
1.2创建线程方式二(推荐:java可多实现):实现Runable接口,重写run方法,执行线程需要丢入runnable接口实现类,调用start方法启动线程
//创建线程方式二:实现Runable接口,重写run方法,执行线程需要丢入runnable接口实现类,调用start方法启动线程
public class MyThirdThread implements Runnable{
@Override
public void run() {
//run方法体
for (int i = 0; i < 20 ; i++) {
System.out.println("看代码"+i);
}
}
public static void main(String[] args) {
//创建runnable接口的实现类
MyThirdThread myThirdThread = new MyThirdThread();
//创建线程对象,通过线程对象来开启线程
//Thread thread = new Thread(myThirdThread);
//thread.start();
//上面两行的简写
new Thread(myThirdThread).start();
for (int i = 0; i < 2000; i++) {
System.out.println("学习++"+i);
}
}
}
执行结果:同第一种方式一样:主程序和创建的线程是交叉运行的,也就是并行
1.3 创建线程方式三(了解):具体实现步骤入下图
//线程创建方式3,:实现callable接口
public class MyCallable implements Callable<Boolean> {
private String url; //网络图片地址
private String path; //保存文件的地方
public MyCallable(String url, String path){
this.url = url;
this.path = path;
}
@Override
public Boolean call() {
WebDownLoader webDownLoader = new WebDownLoader();
webDownLoader.downloader(url, path);
System.out.println("下载了文件为:"+path);
return true;
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
MyCallable t1 = new MyCallable("https://avatar.csdnimg.cn/2/B/3/3_qq_40147863_1561001861.jpg", "D:1.jpg");
MyCallable t2 = new MyCallable("https://csdnimg.cn/medal/blog_expert_medal@240.png", "D:2.jpg");
MyCallable t3 = new MyCallable("https://csdnimg.cn/medal/qiandao1@240.png", "D:3.jpg");
//创建执行服务:
ExecutorService ser = Executors.newFixedThreadPool(3);
//提交执行
Future<Boolean> result1 = ser.submit(t1);
Future<Boolean> result2 = ser.submit(t2);
Future<Boolean> result3 = ser.submit(t3);
//获取结果
Boolean bol1 = result1.get();
Boolean bol2 = result2.get();
Boolean bol3 = result3.get();
System.out.println(bol1);
System.out.println(bol2);
System.out.println(bol3);
//关闭服务
ser.shutdown();
}
}
//下载器
class WebDownLoader{
//下载方法
public void downloader(String url, String path){
try {
FileUtils.copyURLToFile(new URL(url), new File(path));
} catch (IOException e) {
e.printStackTrace();
System.out.println("IO异常,downloader方法出现问题");
}
}
}
1.3.1 实现callable创建线程好处:
1.可以定义返回值
2.可以抛出异常
不好的是实现方式复杂一些。
1.3.2 对比和实现runnable接口的不同
2、线程涉及到的静态代理模式
2.1 普通的静态代理模式
public class StaticProxy {
public static void main(String[] args) {
new WinddingProxy(new You()).happyMarry();
}
}
//先写一个要结婚的接口,每个要结婚的类都要实现它
interface Marry{
//结婚方法
public void happyMarry();
}
//你要结婚了,实现结婚的接口
class You implements Marry{
@Override
public void happyMarry() {
System.out.println("你结婚真开心");
}
}
//代理类 ,找个婚庆公司帮你结婚
class WinddingProxy implements Marry{
private Marry target; //代理的具体要结婚的对象
public WinddingProxy(Marry target){ //具体结婚对象通过构造器传入
this.target = target;
}
@Override
public void happyMarry() { // 可以再这里加上一些其他方法
target.happyMarry(); //具体对象结婚 //这里也可以
}
}
总结:真实对象和代理对象都需要实现同一个接口,代理对象要代理真是角色
好处:代理对象可以做很多真实对象做不了的事情,真实对象可以专注做自己的事情
2.2 线程源码结构(线程可以抽出和上面静态代理例子相同的结构,通过对比可以发现线程就是通过静态代理来实现的)
Runnable源码(同Marry接口)
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
Thread 部分源码(同WinddingProxy 代理类)
public
class Thread implements Runnable {
/* What will be run. */
private Runnable target;
public Thread(Runnable target) {
init(null, target, "Thread-" + nextThreadNum(), 0);
}
private void init(ThreadGroup g, Runnable target, String name,
long stackSize, AccessControlContext acc,
boolean inheritThreadLocals) {
//省略了......
this.target = target; //重点看这里
省略了......
}
@Override
public void run() {
if (target != null) {
target.run();
}
}
}
我们平常写的方法普通方法并实现了Runnable接口的类(同真实角色You类)
public class MyFirshThread extends Thread{
@Override
public void run() {
//run方法体
for (int i = 0; i < 20 ; i++) {
System.out.println("看代码"+i);
}
}
}
由此可以得出结论:线程就是通过静态代理来实现的。Runnable是接口,里面有一个run方法, Thread是代理类 可以代理实现Runnable接口的类的对象去执行run方法, 我们实现Runnable接口的类是真实类