Java多线程-1
线程创建
继承Thread类
实现Runnable接口
实现Callable接口 (了解)
一、继承Thread类
- 自定义线程类继承Thread类
- 重写run() 方法, 编写线程执行体
- 创建线程对象, 调用start() 方法启动线程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public class TestThread1 extends Thread { @Override public void run() { for (int i = 0; i < 20; i++) { System.out.println("我在看代码" + i); } } public static void main(String[] args) { TestThread1 testThread1 = new TestThread1(); testThread1.start(); for (int i = 0; i < 20; i++) { System.out.println("我在学习多线程" + i); } } }
|
实现简单下载器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| public class TestThread2 extends Thread { private String url; private String name;
public TestThread2(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) { TestThread2 t1 = new TestThread2("https://z3.ax1x.com/2021/10/15/58F85q.jpg", "image/dog1.jpg"); TestThread2 t2 = new TestThread2("https://z3.ax1x.com/2021/10/15/58F85q.jpg", "image/dog2.jpg"); TestThread2 t3 = new TestThread2("https://z3.ax1x.com/2021/10/15/58F85q.jpg", "image/dog3.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 (IOException e) { e.printStackTrace(); System.out.println("IO异常,downloader方法出现问题"); } } }
|
二、实现Runnable接口
- 定义MyRunnable类实现Runnable接口
- 实现run() 方法, 编写线程执行体
- 创建线程对象, 调用start() 方法启动线程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| / 创建线程方式2: 实现runnable接口, 重写run方法, 执行线程须丢入runnable接口实现类。调用start方法 public class TestThread3 implements Runnable{ @Override public void run() { for (int i = 0; i < 20; i++) { System.out.println("我在看代码" + i); } }
public static void main(String[] args) { TestThread3 testThread3 = new TestThread3();
new Thread(testThread3).start();
for (int i = 0; i < 20; i++) { System.out.println("我在学习多线程" + i); } } }
|
三、实现Callable接口
1. 实现callable接口, 需要返回值类型
1. 重写call方法, 需要抛出异常
1. 创建目标对象
4. 创建执行服务 ExecutorService ser = Executors.newFixedThreadPool(3);
1. 提交执行 Future<Boolean> r1 = ser.submit(t1);
1. 获取结果 Boolean rs1 = r1.get();
1. 关闭服务 ser.shutdownNow();
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
|
public class TestCallable implements Callable<Boolean> {
private String url; private String name;
public TestCallable(String url, String name) { this.url = url; this.name = name; }
@Override 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 { TestCallable t1 = new TestCallable("https://z3.ax1x.com/2021/10/15/58F85q.jpg", "image/dog1.jpg"); TestCallable t2 = new TestCallable("https://z3.ax1x.com/2021/10/15/58F85q.jpg", "image/dog2.jpg"); TestCallable t3 = new TestCallable("https://z3.ax1x.com/2021/10/15/58F85q.jpg", "image/dog3.jpg");
ExecutorService ser = Executors.newFixedThreadPool(3); Future<Boolean> r1 = ser.submit(t1); Future<Boolean> r2 = ser.submit(t2); Future<Boolean> r3 = ser.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); ser.shutdownNow();
} }
class WebDownloader { public void downloader(String url, String name) { try { FileUtils.copyURLToFile(new URL(url), new File(name)); } catch (IOException e) { e.printStackTrace(); System.out.println("IO异常,downloader方法出现问题"); } } }
|
小结
不建议使用 继承Thread类 : 避免OOP单继承局限性
推荐使用 实现Runnable接口 :
方便灵活,方便同一个对象被多个线程使用
Callable好处: 可以定义返回值, 可以抛出异常
线程不安全
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
|
public class TestThread4 implements Runnable { private int ticketNums = 10; @Override public void run() { while (true) { if (ticketNums <= 0) break; try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); }
System.out.println(Thread.currentThread().getName() + "-->拿到了第" + ticketNums-- + "票"); } }
public static void main(String[] args) { TestThread4 ticket = new TestThread4();
new Thread(ticket, "小明").start(); new Thread(ticket, "老师").start(); new Thread(ticket, "黄牛党").start();
} }
|
龟兔赛跑例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| public class Race implements Runnable { private static String winner;
@Override public void run() { for (int i = 0; i <= 100; i++) { if (Thread.currentThread().getName().equals("兔子") && i%10 ==0){ try { Thread.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } }
boolean flag = gameOver(i); if (flag) break;
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(); } }
|
静态代理模式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
|
public class StaticProxy { public static void main(String[] args) {
new Thread(()-> System.out.println("I LOVE YOU")).start();
You you = new You(); WeddingCompany weddingCompany = new WeddingCompany(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 after() { System.out.println("结婚之后, 收尾款"); }
private void before() { System.out.println("结婚之前,布置现场"); } }
|
Lamda表达式
避免匿名内部类定义过多
实质属于函数式编程的概念
(params) -> expression[表达式]
(params) ->statement[语句]
(params) -> {statements}
避免匿名内部类定义过多
只留下核心代码
函数式接口:
任何接口,如果只包含唯一一个抽象方法,那他就是一个函数式接口
1 2 3
| public interface Runnable{ public abstract void run(); }
|
对于函数式接口,我们可以通过lambda表达式来创建该接口的对象
1 2 3 4 5 6 7 8 9 10 11 12
| public class TestLambda2 { public static void main(String[] args) { Ilove love = (int a) -> { System.out.println("I love you --> " + a); }; love.love(520); } }
interface Ilove{ void love(int a); }
|
简化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| Ilove love = (a)->{ System.out.println("I love you --> " + a); }; love.love(520);
Ilove love = a->{ System.out.println("I love you --> " + a); }; love.love(520);
Ilove love = a-> System.out.println("I love you --> " + a); love.love(520);
|
总结
lambda表达式只有一行代码的情况下才能简化成为1行,如果有多行,用
{} 包裹
前提是: 接口为函数式接口