java多线程
线程简介
Process与Thread
进程是系统资源分配的最小单位,线程是CPU调度和执行的最小单位,一个进程中可以包含多个线程。
线程的创建
- Thread 类
- Runnable接口
- Callable接口
Thread类
线程开启不一定立即执行,由CPU调度执行
//创建线程方法一: 继承Thread类 重写run方法
public class MyThread extends Thread{
@Override
public void run() {
for(int i=0;i<=5;i++){
try {
sleep(1000); //延时1秒
System.out.println("我的线程--------------"+i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws InterruptedException {
MyThread thread=new MyThread();
thread.start(); //start方法主线程与子线程交替执行
for(int i=0;i<=5;i++){
System.out.println("主线程---"+i);
sleep(1000);
}
}
}
如果换成run 则在主线程中按顺序执行
多线程下载图片Demo
/**
* 多线程同步下载图片
*/
public class Demo_01 extends Thread {
private String url;
private String name;
public Demo_01(String url,String name){
this.url=url;
this.name=name;
}
//下载图片线程的执行体
@Override
public void run() {
WebDownloader webDownloader=new WebDownloader();
webDownloader.downloader(url,name);
System.out.println("下载了文件名:"+name);
}
public static void main(String[] args) {
Demo_01 t1=new Demo_01("https://phq-1304846428.cos.ap-nanjing.myqcloud.com/pic.jpg","1.jpg");
Demo_01 t2=new Demo_01("https://phq-1304846428.cos.ap-nanjing.myqcloud.com/typora_pic/typora-icon.png","2.jpg");
Demo_01 t3=new Demo_01("https://phq-1304846428.cos.ap-nanjing.myqcloud.com/typora_pic/QQ%E5%9B%BE%E7%89%8720210418141559.jpg","3.jpg");
t1.start();
t2.start();
t3.start();
}
}
//下载器
class WebDownloader{
//下载方法
public void downloader(String url,String name ){
try {
FileUtils.copyURLToFile(new URL(url),new File(name));
}catch (Exception e){
e.printStackTrace();
System.out.println("IO异常,Downloader方法出现问题");
}
}
}
Runnable接口
//创建线程方法2:实现Runnable接口 ,重写run方法
//执行线程需要丢入Runnable接口实现类 调用start()方法
public class RunnableThread implements Runnable{
@Override
public void run() {
for (int i=0;i<=5;i++){
System.out.println("Runnable 线程------"+i);
}
}
public static void main(String[] args) {
RunnableThread rt=new RunnableThread();
//丢入Runnable接口实现类
new Thread(rt).start();
for(int i=0;i<=5;i++){
System.out.println("主线程---"+i);
}
}
}
两种方式的区别
- 继承Thread类
子类继承Thread类具备多线程能力
启动线程: 子类对象.start();
不建议使用 : 避免OOP单继承局限性
- 实现Runnable接口
实现接口Runnable具有多线程能力
启动线程: 传入目标对象+Thread对象.start();
推荐使用:避免单继承局限性,灵活方便,方便同一个对象被多个线程使用
测试多个线程操作同一个对象—买票问题
//发现问题:多个线程操作同一个资源的情况下 线程不安全 数据紊乱
public class TestThread implements Runnable{
private int ticketnumber=10;
@Override
public void run() {
while(true){
if(ticketnumber<=0){
break;
}
try {
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName()+"-->拿到了第"+ticketnumber-- +"张票。");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
TestThread ts=new TestThread();
new Thread(ts,"小明").start();
new Thread(ts,"张三").start();
new Thread(ts,"罗翔").start();
}
}
模拟龟兔赛跑
public class Race implements Runnable{
private String winner;
@Override
public void run() {
for (int i = 0; i <= 100; i++) {
//判断比赛是否结束
boolean flag=gameOver(i);
if(flag){
break;
}
//模拟兔子休息
if(Thread.currentThread().getName().equals("兔子")&& i%10==0){
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+"--->跑了"+i+"步。");
}
}
private boolean gameOver(int steps){
if(winner!=null){
return true;
}if(steps>=100){
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();
}
}
Callable接口
public class CallableThread implements Callable<Boolean> {
private String url;
private String name;
public CallableThread(String url,String name){
this.url=url;
this.name=name;
}
public Boolean call() {
WebDownloader webDownloader=new WebDownloader();
webDownloader.downloader(url,name);
System.out.println("下载了文件名:"+name);
return true;
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
CallableThread t1=new CallableThread("https://phq-1304846428.cos.ap-nanjing.myqcloud.com/pic.jpg","1.jpg");
CallableThread t2=new CallableThread("https://phq-1304846428.cos.ap-nanjing.myqcloud.com/typora_pic/typora-icon.png","2.jpg");
CallableThread t3=new CallableThread("https://phq-1304846428.cos.ap-nanjing.myqcloud.com/typora_pic/QQ%E5%9B%BE%E7%89%8720210418141559.jpg","3.jpg");
//创建执行服务
ExecutorService service= Executors.newFixedThreadPool(3);
//提交执行
Future<Boolean> r1=service.submit(t1);
Future<Boolean> r2=service.submit(t2);
Future<Boolean> r3=service.submit(t3);
//获取结果
boolean rs1=r1.get();
boolean rs2=r2.get();
boolean rs3=r3.get();
System.out.println(rs1);
System.out.println(rs2);
System.out.println(rs3);
//关闭服务
service.shutdown();
}
}
Callable的好处:
- 可以定义返回值
- 可以抛出异常
静态代理模式
线程底部实现原理
/**
* 代理的思想
*真实对象和代理对象都要实现统一接口
* 代理对象必须代理真实角色
*
* 好处:代理对象可以做很多真实对象做不了的事
* 真实对象可以专注做自己的事
*/
public class staticProxy {
public static void main(String[] args) {
WeddingCompany weddingCompany=new WeddingCompany(new You());
weddingCompany.HappyMarry();
}
}
interface Marry{
void HappyMarry();
}
//真实角色 你去结婚
class You implements Marry{
@Override
public void HappyMarry() {
System.out.println("我要结婚了,开心");
}
}
//代理角色,婚庆公司帮你结婚
class WeddingCompany implements Marry{
private Marry target;
public WeddingCompany(Marry target) {
this.target = target;
}
@Override
public void HappyMarry() {
before();
this.target.HappyMarry();//这就是真实对象
after();
}
private void before() {
System.out.println("代理:结婚之前笑嘻嘻");
}
private void after() {
System.out.println("代理:结婚之后哭唧唧");
}
}
Lamda表达式
- 避免匿名内部类定义过多
- 让代码看起来很简洁,去掉了一堆没有意义的代码 只保留核心的逻辑
- 其实质属于函数式编程的概念
函数式接口 Functional Interface
- 任何接口,如果只包含唯一的抽象方法,那么他就是一个函数式接口
- 对于函数式接口,可以用lamda表达式来创建该接口的对象
lamda的简化过程:
/**
*
* 推导lamda表达式
*/
public class LamdaTest {
//3:静态内部类
static class Like1 implements ILike{
@Override
public void lamda() {
System.out.println("静态内部类--->I like lamda1.");
}
}
public static void main(String[] args) {
ILike like=new Like();
like.lamda();
like=new Like1();
like.lamda();
//4:局部内部类
class Like2 implements ILike{
@Override
public void lamda() {
System.out.println("局部内部类---> I like lamda2.");
}
}
like=new Like2();
like.lamda();
//5.匿名内部类 没有类的名称 只能借助父类或者接口
like=new ILike() {
@Override
public void lamda() {
System.out.println("匿名内部类-->I like lamda3.");
}
};
like.lamda();
//6:用lamda简化
like=()-> {
System.out.println("lamda简化-->I like lamda4.");
};
like.lamda();
}
}
//1:定义一个函数式接口
interface ILike{
void lamda();
}
//2:实现类
class Like implements ILike{
@Override
public void lamda() {
System.out.println("I like lamda.");
}
}
简化1:去掉参数类型
简化2:去掉括号