对Thread线程的学习

Thread线程

创建线程方式一:继承Thread类,重写run()方法,调用start开启线程 (start是两条路 同时执行)

启动线程:子类对象.start()

不建议使用:避免OOP单继承局限性

public class TestThread01 extends Thread{
     @Override
     public void run() {
         //run方法线程体
         for (int i = 0; i < 10; i++) {
             System.out.println("学习Java--"+i);
         }
     }
 ​
     public static void main(String[] args) {
         //main线程
 ​
         //创建一个线程对象
         TestThread01 testThread01 = new TestThread01();
 ​
         //调用start()方法开启线程
         testThread01.start();
 ​
         for (int i = 0; i < 10; i++) {
             System.out.println("多线程"+i);
         }
     }
 }

创建线程方式2:实现runnable接口,重写run方法,执行线程需要丢入runnable接口实现类,调用start方法

启动线程:传入目标对象 + Thread对象.start()

不建议使用:避免单继承局限性,灵活方便,方便同一个对象被多个线程使用

 public class TestThread03 implements Runnable{
     @Override
     public void run() {
         for (int i = 0; i < 20; i++) {
             System.out.println("我在写代码---"+i);
         }
     }
 ​
     public static void main(String[] args) {
         //创建runnable接口的实现类对象
         TestThread03 testThread03 = new TestThread03();
 ​
         //创建线程对象,通过线程对象来开启我们的线程,代理
 //        Thread thread = new Thread(testThread03);
 //
 //        thread.start();
 ​
         new Thread(testThread03).start();
 ​
         for (int i = 0; i < 10; i++) {
             System.out.println("学习多线程---"+i);
         }
     }
 }

创建线程方式三:实现callable接口

好处:1. 可以定义返回值;2. 可以抛出异常

//创建线程方式三:实现callable接口
 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://uploadstatic.mihoyo.com/puzzle/upload/puzzle/2022/08/12/f8f8b39b79082490dc7a51cb58c033a4_1886787457893712308.jpg?x-oss-process=image/format,webp/quality,Q_90","1.jpg");
         TestCallable t2 = new TestCallable("https://uploadstatic.mihoyo.com/puzzle/upload/puzzle/2022/08/12/f8f8b39b79082490dc7a51cb58c033a4_1886787457893712308.jpg?x-oss-process=image/format,webp/quality,Q_90","2.jpg");
         TestCallable t3 = new TestCallable("https://uploadstatic.mihoyo.com/puzzle/upload/puzzle/2022/08/12/f8f8b39b79082490dc7a51cb58c033a4_1886787457893712308.jpg?x-oss-process=image/format,webp/quality,Q_90","3.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方法出现问题");
         }
     }
 }

总结:线程开启不一定立即执行,由CPU调度执行

Lamdba表达式

public class TestLamdba2 {
     public static void main(String[] args) {
         //ILove love = null;
         
         //1. lamdba简化
         ILove love = (int a)->{
             System.out.println("I love you-->"+a);
         };
 ​
         //简化1. 参数类型
         love = (a)->{
             System.out.println("I love you-->"+a);
         };
 ​
         //简化2. 简化括号
         love = a->{
             System.out.println("I love you-->"+a);
         };
 ​
         //简化3. 去掉大括号
         love = a -> System.out.println("I love you-->"+a);
 ​
         love.love(0);
     }
 }
 //定义一个函数式接口
 interface ILove{
     void love(int a);
 }

总结:

  1. lamdba表达式只能有一行代码的情况下才能简化成为一行,如果有多行,那么就用代码块包裹。

  2. 前提是接口为函数式接口

  3. 多个参数也可以去掉参数类型,要去掉就都去掉,必须加上括号

静态代理模式

public class StacticProxy {
    public static void main(String[] args) {
        new Thread(()-> System.out.println("520")).start();

//        WeddingCompany weddingCompany = new WeddingCompany(new You());
//        weddingCompany.HappyMarry();
        new WeddingCompany(new You()).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("都没了");
    }
}

总结:

  1. 真实对象和代理对象都要实现同一个接口

  2. 代理对象要代理真实对象

好处:

  1. 代理对象可以做很多真实对象做不了的事件

  2. 真实对象专注做自己的事情

线程停止

public class TestStop implements Runnable{
 ​
     //1. 设置一个标识位
     private boolean flag = true;
 ​
     @Override
     public void run() {
         int i = 0;
         while (flag){
             System.out.println("run.....Thread" + i++);
         }
     }
 ​
     //2. 设置一个公开的方法停止线程,转换标志位
     public void stop(){
         this.flag = false;
     }
 ​
     public static void main(String[] args) {
         TestStop testStop = new TestStop();
 ​
         new Thread(testStop).start();
 ​
         for (int i = 0; i < 100; i++) {
             System.out.println("main-->"+i);
             if (i == 90){
                 testStop.stop();
                 System.out.println("线程停止");
             }
         }
     }
 }

建议:

  1. 建议线程正常停止--->利用次数,不建议死循环

  2. 建议使用标志位--->设置一个标志位

  3. 不要使用stop或者destroy等过时或者JDK不建议使用的方法

线程礼让—Yield

public class TestYield {
     public static void main(String[] args) {
         MyYield myYield = new MyYield();
         new Thread(myYield,"a").start();
         new Thread(myYield,"b").start();
     }
 }
 class MyYield implements Runnable{
     @Override
     public void run() {
         System.out.println(Thread.currentThread().getName()+"线程开始执行");
         Thread.yield();
         System.out.println(Thread.currentThread().getName()+"线程停止执行");
     }
 }

线程优先级

  • 线程的优先级用数字表示,范围从1~10

    • Thread.MIN_PRIORITY = 1;

    • Thread.MAX_PRIORITY = 10;

    • Thread.NORM_PRIORITY = 5;

  • 使用以下方法改变或获取优先级

    • getPriority()

    • setPriority(int XXX)

注意:优先级的设定建议在start()调度前

同步块

  • 同步块:synchronized ( Obj ) { }

  • Obj称之为同步监视器

    • Obj可以是任何对象,但是推荐使用共享资源作为同步监视器

    • 同步方法中无需指定同步监视器,因为同步方法的同步监视器就是this,就是这个对象本身,或者是class

  • 同步监视器的执行过程

    1. 第一个线程访问,锁定同步监视器,执行其中代码.

    2. 第二个线程访问,发现同步监视器被锁定,无法访问.

    3. 第一个线程访问完毕,解锁同步监视器.

    4. 第二个线程访问,发现同步监视器没有锁,然后锁定并访问

线程通信(生产者与消费者问题)

解决方式1:管程法

//测试:生产者消费者模型-->利用缓冲区解决:管程法
 public class TestPC {
     public static void main(String[] args) {
         SynContainer container = new SynContainer();
         new Producer(container).start();
         new Consumer(container).start();
     }
 }
 ​
 //生产者
 class Producer extends Thread{
     SynContainer container;
 ​
     public Producer(SynContainer container){
         this.container = container;
     }
 ​
     //生产
     @Override
     public void run() {
         for (int i = 0; i < 100; i++) {
             System.out.println("生成了"+i+"原石");
             container.push(new Chicken(i));
         }
     }
 }
 ​
 //消费者
 class Consumer extends Thread{
     SynContainer container;
 ​
     public Consumer(SynContainer container){
         this.container = container;
     }
 ​
     //消费
     @Override
     public void run() {
         for (int i = 0; i < 100; i++) {
             System.out.println("消费了-->"+container.pop().id+"原石");
         }
     }
 }
 ​
 //产品
 class Chicken{
     int id;
     public Chicken(int id){
         this.id = id;
     }
 }
 ​
 //缓冲区
 class SynContainer{
     //需要一个容器大小
     Chicken[] chickens = new Chicken[10];
     //容器计数器
     int count = 0;
 ​
     //生产者放入产品
     public synchronized void push(Chicken chicken){
         while (count == 10){
             try{
                 this.wait();
             } catch (InterruptedException e) {
                 e.printStackTrace();
             }
         }
         chickens[count] = chicken;
         count++;
         this.notifyAll();
     }
 ​
     //消费者消费产品
     public synchronized Chicken pop(){
         while (count == 0){
             try{
                 this.wait();
             } catch (InterruptedException e) {
                 e.printStackTrace();
             }
         }
         count--;
         Chicken chicken = chickens[count];
         this.notifyAll();
         return chicken;
     }
 }

解决方式2:信号灯法

//测试:生产者消费者模型-->利用标志位解决:信号灯法
 public class TestPC2 {
     public static void main(String[] args) {
         TV tv = new TV();
         new Player(tv).start();
         new Watcher(tv).start();
     }
 }
 //生产者--演员
 class Player extends Thread{
     TV tv;
     public Player(TV tv){
         this.tv = tv;
     }
 ​
     @Override
     public void run() {
         for (int i = 0; i < 10; i++) {
             if (i%2==0){
                 this.tv.play("快乐大本营");
             }else {
                 this.tv.play("抖音");
             }
         }
     }
 }
 ​
 //消费者--观众
 class Watcher extends Thread{
     TV tv;
     public Watcher(TV tv){
         this.tv = tv;
     }
 ​
     @Override
     public void run() {
         for (int i = 0; i < 10; i++) {
             tv.watch();
         }
     }
 }
 //产品--节目
 class TV{
     //演员表演,观众等待   T
     //观众观看,演员等待   F
     String voice;  //表演的节目
     boolean flag = true;
 ​
     //表演
     public synchronized void play(String voice){
         if (!flag){
             this.watch();
         }
         System.out.println("演员表演了:"+voice);
         //通知观众观看
         this.notifyAll();  //通知唤醒
         this.voice = voice;
         this.flag = !this.flag;
     }
 ​
     //观看
     public synchronized void watch(){
         if (flag){
             try {
                 this.wait();
             } catch (InterruptedException e) {
                 e.printStackTrace();
             }
         }
         System.out.println("观看了:"+voice);
         //通知演员表演
         this.notifyAll();
         this.flag = ! this.flag;
     }
 }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值