首页 > 其他分享 >线程基础(上)

线程基础(上)

时间:2022-08-27 12:06:59浏览次数:118  
标签:Thread void 基础 System 线程 new public

1.创建线程一:继承Thread 类

  • 子类继承Thread 类具备多线程能力

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

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

创建线程方式一:继承Thread类,重写run()方法,调用start开启线程 注意:线程开启不一定立即执行,由CPU调度执行

public class TestThread extends Thread {
   @Override
   public void run() {
       //run方法线程体
       for (int i = 0; i < 200; i++) {
           System.out.println("我在看代码~~~");
      }
  }

   public static void main(String[] args) {
       //main线程,主线程
       //创建一个线程对象
       TestThread testThread = new TestThread();
       //调用start()方法开启线程
       testThread.start();
       for (int i = 0; i < 1000; i++) {
           System.out.println("我在学习多线程");
      }
  }
}
import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;
import java.net.URL;

//练习Thread,实现多线程同步下载图片
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://tse4-mm.cn.bing.net/th/id/OIP-C.nip7Mn96BGdUdjG6zOWRnAHaLH?w=186&h=279&c=7&r=0&o=5&dpr=1.05&pid=1.7","1.jpg");
       TestThread2 t2 = new TestThread2("https://tse2-mm.cn.bing.net/th/id/OIP-C.Jtsv_OsQj2kn-3aKZrWr2wHaJp?pid=ImgDet&rs=1","2.jpg");
       TestThread2 t3 = new TestThread2("https://img.zcool.cn/community/015ea15d5cbdf6a8012187f458d58f.jpg@1280w_1l_2o_100sh.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 (IOException e) {
           e.printStackTrace();
           System.out.println("IO异常,downloader方法出现问题");
      }
  }
}

二、创建线程方式二:实现Runable接口

  • 定义MyRunnable类实现Runable接口

  • 重写run()方法,编写线程执行体

  • 创建线程对象,调用start()方法启动线程

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

实现runnable接口,重写run()方法,执行线程需要丢入runnable接口实现类,调用start方法

public class TestThread3 implements Runnable {
   @Override
   public void run() {
       for (int i = 0; i < 20; i++) {
           System.out.println("run方法中的输出语句");
      }
  }

   public static void main(String[] args) {
       //创建Runnable接口的实现类对象
       TestThread3 testThread3 = new TestThread3();
       //创建线程对象,通过线程对象来开启我们的线程,代理
       Thread thread = new Thread(testThread3);
       thread.start();
       //new Thread(testThread3).start();
       for (int i = 0; i < 1000; i++) {
           System.out.println("主线程的输出语句");
      }
  }
}

初识并发问题:多个线程同时操作同一个对象

发现问题:多个线程操作同一个资源的情况下,线程不安全

龟兔赛跑

package thread;

//模拟龟兔赛跑
public class Race implements Runnable{
   private String winner;
   @Override
   public void run() {
       for (int i = 0; i <= 100; i++) {
           //模拟兔子睡觉
           if(Thread.currentThread().getName().equals("兔子")&&i%10 ==0){
               try {
                   Thread.sleep(5);
              } catch (InterruptedException e) {
                   e.printStackTrace();
              }
          }
           //判断比赛是否结束
           boolean flag = jieguo(i);
           if (flag){
               break;
          }
           System.out.println(Thread.currentThread().getName()+"-->跑了"+i+"步");
      }
  }

   //判断是否完成比赛
   private boolean jieguo (int steps){
       if (winner !=null){ //已经存在胜利者
           return true;
      }else 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();
//实现runnable接口的对象,丢到Thread里面
       new Thread(race,"乌龟").start();
       new Thread(race,"兔子").start();
  }
}

静态代理模式总结:

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

  • 代理对象代理真实角色

lambda表达式

函数式接口 Functional Interface:只包含唯一一个抽象方法。对于函数式接口,我们可以通过lambda表达式来创建该接口的对象。

使用Lambda 表达式的前提是函数式接口。

Lambda的推导

package thread;
/*推导lambda表达式*/
public class TestLambda01 {
   //3、静态内部类
   static class Like2 implements ILike{
       @Override
       public void lambda() {
           System.out.println("静态内部类的输出");
      }
  }

   public static void main(String[] args) {
       //接口去new一个他的实现类
       ILike like = new Like(); // 实现类
       like.lambda();

       like =new Like2(); //静态内部类
       like.lambda();

       //4、局部内部类
       class Like3 implements ILike{
           @Override
           public void lambda() {
               System.out.println("局部内部类的输出");
          }
      }
       like = new Like3();
       like.lambda();

       //5、匿名内部类:没有类的名称,必须借助接口或者父类
       like = new ILike() {
           @Override
           public void lambda() {
               System.out.println("匿名内部类的输出");
          }
      };
       like.lambda();

       //6、用Lambda简化
       like =()->{
           System.out.println("lambda的输出");
      };
       like.lambda();
  }
}


//1、定义一个函数式接口
interface ILike{
   void lambda();
}

//2、实现类
class Like implements ILike{
   @Override
   public void lambda() {
       System.out.println("实现类的输出");
  }
}

Lambda表达式的简化

public class TestLambda02 {
   public static void main(String[] args) {
       Study1 stu = (int a)->{
           System.out.println("输出"+a);
      };
       stu.add(5);

       //简化1、去掉参数类型(多个参数也可以,必须加括号)
       stu = (a)->{
           System.out.println("输出"+a);
      };
       stu.add(8);

       //简化2、简化括号
       stu = a->{
           System.out.println("输出"+a);
      };
       stu.add(9);

       //简化3、去掉花括号(在只有一行的情况下)
       stu = a-> System.out.println("666"+a);
       stu.add(888);
  }
}

interface Study1{
   void add(int a);
}

线程状态

  • 创建状态:Thread t = new Thread()线程对象一旦创建就进入到了新生状态

  • 就绪状态:当调用start()方法,线程立即进入就绪状态,但不意味着立即调度执行

  • 运行状态:进入运行状态,线程才真正执行线程体的代码块

  • 阻塞状态:当调用sleep,wait 或同步锁定时,线程进入阻塞状态,就是代码不往下执行,阻塞时间解除后,重新进入就绪状态,等待CPU调度执行。

  • 死亡状态:线程中断或者结束,一旦进入死亡状态,就不能再次启动。

停止线程

不推荐使用JDK提供的stop()、destroy()方法【已废弃】;推荐线程自己停止下来

建议使用一个标志位进行终止变量当flag=false,则终止线程运行。

//测试停止线程
// 1、建议线程正常停止---->利用次数,不建议死循环。
// 2、建议使用标志位--->设置一个标志位
public class TestStop implements Runnable{
   // 1、设置一个标志位
   private boolean flag = true;

   @Override
   public void run() {
       int i = 0;
       while (flag){
           System.out.println("线程运行"+ 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 < 1000; i++) {
           System.out.println("main---"+i);
           if (i==800){
               testStop.stop();
               System.out.println("线程该停止了");
          }

      }
  }
}

线程休眠

  1. sleep需要抛出异常

  2. sleep时间达到后线程进入就绪状态

  3. sleep可以模拟网络延时、倒计时等。

  4. 每一个对象都有一个锁,sleep不会释放锁;※※

模拟网络延时:放大问题的发生性

package thread;

//模拟网络延时
public class TestSleep implements Runnable{
   //火车票数
   private int ticketNums = 10;
   @Override
   public void run() {
       while (true){
           if (ticketNums<=0){
               break;
          }
           //模拟延时
           try {
               Thread.sleep(2000);
          } catch (InterruptedException e) {
               e.printStackTrace();
          }
           System.out.println(Thread.currentThread().getName()+"拿到了第"+ticketNums--+"张票");
      }
  }

   public static void main(String[] args) {
       TestSleep ticket = new TestSleep();

       new Thread(ticket,"小明星").start();
       new Thread(ticket,"老师").start();
       new Thread(ticket,"黄牛").start();
  }
}

模拟倒计时

package thread;


import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.logging.SimpleFormatter;

public class TestSleep2 {
    public static void main(String[] args) {
        // 打印当前系统时间
        Date time = new Date(System.currentTimeMillis());
        while (true){
            try {
                Thread.sleep(1000);
                System.out.println(new SimpleDateFormat("HH:mm:ss").format(time));
                time = new Date(System.currentTimeMillis());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    //模拟倒计时,直接在main方法中调用turnDown()方法
    public static void turnDown() throws InterruptedException {
        int num = 10;
        while (true){
            Thread.sleep(1000);
            System.out.println(num--);
            if(num<=0){
                break;
            }
        }
    }

}

线程礼让:礼让不一定成功

//测试礼让线程,礼让不一定成功
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()+"结束");
  }
}

Join

想象为线程插队

public class TestJoin implements Runnable{
   public static void main(String[] args) throws InterruptedException {
       TestJoin testJoin = new TestJoin();
       Thread thread = new Thread(testJoin);
       thread.start();
       for (int i = 0; i < 500; i++) {
           if (i==100){
               thread.join();
          }
           System.out.println("main"+i);
      }
  }

   @Override
   public void run() {
       for (int i = 0; i < 200; i++) {
           System.out.println("线程vip"+i);
      }
  }
}

 

 

标签:Thread,void,基础,System,线程,new,public
From: https://www.cnblogs.com/znx254825418/p/16630252.html

相关文章

  • kafka基础使用
    生产者/opt/kafka/bin/kafka-console-producer.sh--broker-listkafka.service.consul:9092--topic0bkmonitor_15026750消费者/opt/kafka/bin/kafka-console-consumer.......
  • Nginx分布式框架详解-基础32-36nginx基础配置实例
    nginx基础配置实例需求分析前面我们已经对Nginx服务器默认配置文件的结构和涉及的基本指令做了详细的阐述。通过这些指令的合理配置,我们就可以让一台Nginx服务器正常......
  • MySQL五:InnoDB线程模型
    转载~一、InnoDB线程模型的组成在Innodb存储引擎中,后台线程的主要作用是「负责刷新内存池中的数据,保证缓冲池中的内存缓存的是最近的数据」。此外它会将已经修改的数据文......
  • MySQL十:索引基础知识回顾
    转载~1、索引简介1.1什么是索引索引是对数据库表中一列或多列的值进行排序的一种结构,可以大大提高MySQL的检索速度。索引在MySQL中也叫做key,当表中的数据量越来越大时,......
  • D11(java基础)
    D11(java基础)流概念:内存与存储设备之间传输数据的通道。流的分类按方向:输入流:将存储设备中的内容读入到内存中。输出流:将内存中的内容写入到存储设备中。......
  • UnixBench跑分没有多线程数据的解决办法
    如图,只显示了单核的结果就退出了跑分第一种解决办法是找到UnixBench文件夹下的Run文件,编辑第110行的核数进行修改为自己的服务器核数然后再执行./Run  第二种办法如......
  • C++基础-理解new和delete
    intmain(intargc,charconst*argv[]){ //C风格 int*p=(int*)malloc(sizeof(int)); if(p==NULL){ return-1; } *p=20;//初始化 free(p); int*q=(......
  • Nginx分布式框架详解-基础22-31nginx核心配置文件
    nginx配置文件nginx.conf的文件结构从前面的内容学习中,我们知道Nginx的核心配置文件默认是放在/usr/local/nginx/conf/nginx.conf,本次我们就来学习下nginx.conf的内......
  • JavaSE-Day01-Java基础语法
    Java基础语法注释、标识符、关键字数据类型类型转换变量、常量运算符包机制包的本质就是文件夹一般利用公司域名倒置作为包名eg:www.baidu.com-->com.baidu.www......
  • 基础数据类型之字典
    1.字典的定义使用{}定义字典,括号内用逗号分隔开多个key:value,其中value可以是任意类型,但是key必须是不可变类型且不能重复,是无序的!info=[['name','zhang'],('ag......