3.1 多线程
1. 继承Thread类

package com.threaddd;
// 继承Thread类:1.继承Thread类,重写run方法,调用start开启线程
//总结:注意,线程开启不一定立即执行,有cpu调度执行
public class TestThread1 extends Thread{
//run();重写 override快捷键CTRL + O;
@Override
public void run() {
//run方法线程体
for (int i = 0; i < 200; i++) {
System.out.println("RUN"+i);
}
}
public static void main(String[] args) {
//main线程,主线程
//创建一个主线程
TestThread1 testThread1 = new TestThread1();
//调用start()方法开启线程,而不是run
testThread1.start();
for (int i = 0; i < 200; i++) {
System.out.println("我在学习多线程"+i);
}
}
}
2. 用线程下载网图
package com.threaddd;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
public class TestThread2 extends Thread {
private String url;
private String name;
//构造器
public TestThread2(String url , String name){
this.url = url;
this.name = name;
}
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://img2020.cnblogs.com/blog/1883993/202102/1883993-20210228172150715-1170074631.png","1");
TestThread2 t2 = new TestThread2("https://img2020.cnblogs.com/blog/1883993/202102/1883993-20210228172150715-1170074631.png","2");
TestThread2 t3 = new TestThread2("https://img2020.cnblogs.com/blog/1883993/202102/1883993-20210228172150715-1170074631.png","3");
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方法出现问题");
}
}
}
3. 实现Run able接口
- 定义MyRunable类实现RunAble接口
- 实现run()方法,编写线程执行体
- 创建线程对象,调用Start()方法启动
推荐使用Runable对象,由于Java单继承的局限
总结:
-
继承Thread
- 子类继承Thread类具备多线程能力
- 启动线程:子类对象.start()
- 不建议使用:避免OOP单继承的局限性
-
实现runable接口具有多线程的能力
- 启动线程:传入目标对象+Thread对象.start
- 推荐使用:避免单继承的局限性,灵活方面,方便一个对象被多个线程使用。
例题:火车票
package com.threaddd;
//多个线程同时操作一个同一个对象
//买火车票的例子
public class TrainTicket implements Runnable{
private int tickets = 10;
@Override
public void run() {
while (true){
if(tickets <= 0)
break;
}
//模拟延时
try{
Thread.sleep(200);//单位,毫秒
}catch (InterruptedException e){//当阻塞方法收到中断请求的时候就会抛出InterruptedException异常
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"-->拿到了第"+tickets--+"票");
}
public static void main(String[] args) {
//发现问题,多个线程操作同一个资源,线程不安全,数据紊乱
TrainTicket trainTicket = new TrainTicket();
new Thread(trainTicket,"小明").start();
new Thread(trainTicket,"老师").start();
new Thread(trainTicket,"黄牛").start();
}
}
例题:龟兔赛跑跑
package com.threaddd;
//龟兔赛跑 rabbit tortoise
public class Race implements Runnable{
//一个胜利者
private static String winner ;
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
//模拟兔子睡觉
if(Thread.currentThread().getName().equals("R") && i % 10 == 0)
try{
Thread.sleep(1);
}catch (InterruptedException e){
e.printStackTrace();
}
//判断比赛是否结束,是的话就跳出
if(gameOver(i)){
break;
}
System.out.println(Thread.currentThread().getName()+"跑了第"+i+"步");
}
}
private boolean gameOver (int step){
if (winner != null)
return true;
else if (step >= 100){
winner = Thread.currentThread().getName();
System.out.println("The winner is "+winner);
return true;
}else
return false;
}
public static void main(String[] args) {
Race race = new Race();
new Thread(race,"R").start();
new Thread(race,"tortoise").start();
}
}
4. Callable 接口
创建线程方法3:实现Callable接口
- 实现Callable接口需要返回值类型
- 重写Call方法,需要抛出异常
- 创建目标对象
- 创建执行服务:ExecutorService ser = Executor.newFixedThreadPool(1);
- 提交执行:Future<boolean r1 = result1.get()
- 关闭服务:ser.shutdownNow();
5. 静态代理模式
线程的底部实现原理
总结:
- 这是对象和代理对象都要实现同一个接口
- 代理对象要代理真实角色
好处:
- 代理对象可以做很多正式对象做不了的事
- 真实对象专注做自己的事
package com.threaddd.staticproxy;
import sun.plugin2.main.client.WDonatePrivilege;
public class StaticProxy {
public static void main(String[] args) {
WeddingCompany weddingCompany = new WeddingCompany(new You());//可以直接再这里new You()
weddingCompany.happyMarry();
/*
假如不用代理
You you = new You();
You.happyMarry();
这样每一个人的婚礼都一模一样。用了代理可以真实对象最出更多自己专属的动作
*/
//与多线程的联系
/*
You you = new You();
new Thread(new Runnable() { //lambda表达式?
@Override
public void run() {
System.out.println("I love You");
}
}).start();
new WeddingCompany(new You()).happyMarry();
//上面一行等价于
/*
WeddingCompany weddingCompany1 = new WeddingCompany(you);
weddingCompany1.happyMarry();
*/
*/
}
}
interface Marry{
void happyMarry();
}
class You implements Marry{
@Override
public void happyMarry() {
System.out.println("要结婚了,超开心");
}
}
//WeddingCompany
class WeddingCompany implements Marry{
private Marry target;
//new默认是调用无参构造方法,婚庆公司这里的构造方法需要传入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("结婚之后,统计份子");
}
}

浙公网安备 33010602011771号