目录
进程和线程的基本概念
进程是程序执行和资源分配的基本单位,线程是CPU调度和执行的基本单位;
线程创建的三种方式
1. 继承Thread类
关于Thread类:Thread类继承Object类,同时实现了Runnable接口。
实现方法:①声明一个类,继承Thread类,②重写run()方法,③创建线程对象,调用start()方法。
不建议使用:OOP单继承局限性。
public class TestThread1 extends Thread {
@Override
public void run() {
//重写run()方法
}
public static void main(String[] args){
TestThread1 t = new TestThread1();
t.start();
}
}
举例:网图下载
package demo.thread;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
public class TestThread1 extends Thread {
private String url;
private String fileName;
public TestThread1(String url, String fileName){
this.url = url;
this.fileName = fileName;
}
//执行主体
@Override
public void run() {
//重写run()方法
WebDownloader webDownloader = new WebDownloader();
webDownloader.downloader(url, fileName);
System.out.println(fileName+"已经下载完成");
}
public static void main(String[] args){
TestThread1 t1 = new TestThread1("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1600972938327&di=d93212c74560e6ecb7d766a1452a2a87&imgtype=0&src=http%3A%2F%2Fimage.namedq.com%2Fuploads%2F20190511%2F19%2F1557575056-oBLizxVyGb.jpg", "1.jpg");
TestThread1 t2 = new TestThread1("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1600973064432&di=bdb1cfcf3b886920ddfbfe2329287f59&imgtype=0&src=http%3A%2F%2Fn.sinaimg.cn%2Fsinacn18%2F217%2Fw640h377%2F20181112%2F81e4-hnstwwr1625807.jpg", "2.jpg");
TestThread1 t3 = new TestThread1("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1600973064432&di=6f9d342fd1e57de39db03f283299ffc6&imgtype=0&src=http%3A%2F%2Fc-ssl.duitang.com%2Fuploads%2Fitem%2F201906%2F25%2F20190625105243_xwgss.thumb.400_0.jpg", "3.jpg");
t1.start();
t2.start();
t3.start();
}
}
//下载器类
class WebDownloader{
public void downloader(String url, String fileName){
try {
FileUtils.copyURLToFile(new URL(url), new File(fileName));
} catch (IOException e) {
e.printStackTrace();
System.out.println("dowloader() Exception");
}
}
}
2. 实现Runnable接口
实现方法:①声明一个类,实现Runnable接口,②重写run()方法,③创建实现类对象,创建代理类对象,调用start()方法。
建议使用:避免单线程的局限性,方便同一个对象被多个线程使用。
public class TestThread2 implements Runnable{
@Override
public void run() {
//重写run方法
}
public static void main(String[] args){
TestThread2 t2 = new TestThread2();
Thread t = new Thread(t2);
t.start();
}
}
举例:模拟龟兔赛跑
public class Race implements Runnable {
private static String winner;
@Override
public void run() {
for (int i = 0; i <= 1000; i++) {
boolean flag = gameOver(i);
if(flag){
break;
}
if(i%100 == 0){
System.out.println(Thread.currentThread().getName()+"已经跑了"+i+"米");
}
if(i == 500 && Thread.currentThread().getName().equals("兔子")){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
boolean gameOver(int distance){
if(winner != null)
return true;
else {
if(distance>=1000){
winner = Thread.currentThread().getName();
System.out.println("winner is" + winner);
return true;
}
}
return false;
}
public static void main(String[] args) {
Race race = new Race();
new Thread(race, "兔子").start();
new Thread(race, "乌龟").start();
}
}
3. 实现Callable接口()
实现方法:①声明一个类,实现Callable接口,②重写call方法,③主线程创建执行服务,④提交执行,⑤获取call方法的返回值,⑥关闭服务
优点:①可以定义返回值,②可以抛出异常
import java.util.concurrent.*;
public class TestCallable implements Callable {
@Override
public Object call() throws Exception {
return true;
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
TestCallable testCallable = new TestCallable();
//创建执行任务
ExecutorService service = Executors.newFixedThreadPool(1);
//提交执行
Future<Boolean> result1 = service.submit(testCallable);
//获取结果
boolean r1 = result1.get();
//关闭服务
service.shutdownNow();
}
}
探究Thread类
1. lambda 表达式
优势:
- 避免匿名内部类定义过多
- 可以让代码更简洁
- 去掉没有意义的代码,只留下核心逻辑
函数式接口:任何接口,如果只包含一个抽象方法,那么他就是一个函数式接口。
对于函数式接口,我们可以通过lambda表达式来创建接口的对象。
Runnable接口只有符合函数式接口,因此可以在实现Runnable接口时直接使用Lambda表达式。
各种接口实现举例:
public class Lambda {
//3.静态内部类
static class Work2 implements Person{
@Override
public void career(String str) {
System.out.println(str);
}
}
public static void main(String[] args) {
//4.局部内部类
class Work3 implements Person{
@Override
public void career(String str) {
System.out.println(str);
}
}
//5.匿名内部类
Person person4 = new Person() {
@Override
public void career(String str) {
System.out.println(str);
}
};
//6.Lambda表达式
Person person5 = (str)->{
System.out.println(str);
};
Person person1 = new Work1();
Person person2 = new Work2();
Person person3 = new Work3();
person1.career("student");
person2.career("doctor");
person3.career("teacher");
person4.career("professor");
person5.career("officer");
}
}
//1.定义函数接口
interface Person{
void career(String str);
}
//2.类
class Work1 implements Person{
@Override
public void career(String str) {
System.out.println(str);
}
}
2. 静态代理模式
要求:真实对象和代理对象都需要实现同一个接口,代理对象要代理真实对象。
好处:代理对象可以做很多真实对象做不了的事情,真实对象专注做自己的事情。
以婚庆公司举例:
public class StaticProxy {
public static void main(String[] args) {
You you = new You();
new WeddingCompany(you).happyMarry();
}
}
interface Marry{
void happyMarry();
}
class You implements Marry{
@Override
public void happyMarry() {
System.out.println("happy marry");
}
}
class WeddingCompany implements Marry{
private You target;
public WeddingCompany(You target){
this.target = target;
}
@Override
public void happyMarry() {
before();
this.target.happyMarry();
after();
}
public void before(){
System.out.println("布置婚礼");
}
public void after() {
System.out.println("收尾款");
}
}
在Java中线程的设计就使用了静态代理设计模式,其中自定义线程类实现Runable接口,Thread类也实现了Runalbe接口,在创建子线程的时候,传入了自定义线程类的引用,再通过调用start()方法,调用自定义线程对象的run()方法。实现了线程的并发执行。