多线程

创建线程的方式

  1. 继承Thread类 ; 重写run方法,将继承Thread类的类进行实例化,然后调用该对象的start方法开启线程;(注意:线程开启并不一定立即启用,需等到CPU调度安排)

    public class TestThread extends Thread{
      private String url;
      private String name;

       public TestThread(String url, String name) {
           this.url = url;
           this.name = name;
      }

       //线程的执行体
       @Override
       public void run(){
          webDownloader webDownloader1=new webDownloader();
          webDownloader1.downLoader(url,name);
           System.out.println("下载了文件的名称是:"+name);
      }
       public static void main(String[] args) {
           TestThread thread1=new TestThread("https://www.baidu.com/img/dong_47f08bb2dd6546c9a788f71d7463ce48.gif","1.jpg");
           TestThread thread2=new TestThread("https://www.baidu.com/img/flexible/logo/pc/result.png","2.jpg");
           TestThread thread3=new TestThread("https://pic.rmb.bdstatic.com/bjh/user/0adaa3b9ae82034d4cbd913b354610a3.jpeg?x-bce-process=image/resize,m_lfit,w_200,h_200&autime=14","3.jpg");
           thread1.start();
           thread2.start();
           thread3.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的异常信息"+e);
          }
      }

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

public class TestThread implements Runnable{
   //线程的执行体
   @Override
   public void run(){
       System.out.println("下载了文件的名称是:");
  }
   public static void main(String[] args) {
       //创建runnable接口的实现类的对象
       TestThread thread1=new TestThread();
       //创建线程对象,通过线程对象来开启线程
       new Thread(thread1).start();
  }
}

多线程操作同一个对象的处理

多线程并发的小例子:

//定义票数
private int tickets=10;
//线程的执行体
@Override
public void run(){
   while(true){
      if(tickets<=0){
          break;
      }
      //模拟延时去买票
       try {
           Thread.sleep(200);
      } catch (InterruptedException e) {
           e.printStackTrace();
      }
       System.out.println(Thread.currentThread().getName()+"拿到了第"+tickets--+"张票");
  }
}
public static void main(String[] args) {
   TestThread testThread = new TestThread();
   new Thread(testThread,"小明").start();
   new Thread(testThread,"小红").start();
   new Thread(testThread,"黄牛党").start();
}

龟兔赛跑的小例子

private static   String winner;
  @Override
  public void run() {
      for (int i = 0; i <= 100; i++) {
          if("兔子".equals(Thread.currentThread().getName())&&i%10==0){
              //如果兔子走了10的倍数步,那就歇一会
              try {
                  Thread.sleep(1);
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
          }
          System.out.println(Thread.currentThread().getName()+"跑了-->"+i+"步");
          boolean flag = isGameOver(i);
          if(flag){
              //说明比赛结束
              break;
          }
      }
  }
  //判断比赛是否结束的标志
  public boolean isGameOver(int steps){
      if(winner != null){
          return true;
      }{
          if(steps>=100){
              winner="胜利者为:"+Thread.currentThread().getName();
              System.out.println(winner);
              return true;
          }
      }
      return false;
  }

  public static void main(String[] args) {
      TestThread testThread = new TestThread();
      new Thread(testThread,"兔子").start();
      new Thread(testThread,"乌龟").start();
  }
  1. 实现callable接口

    public class TestThread implements Callable<Boolean> {
       private String url;
       private String name;

       public TestThread(String url, String name) {
           this.url = url;
           this.name = name;
      }

       //线程的执行体
       @Override
       public Boolean call(){
           webDownloader webDownloader1=new webDownloader();
           webDownloader1.downLoader(url,name);
           System.out.println("下载了文件的名称是:"+name);
           return true;
      }
       public static void main(String[] args) throws ExecutionException, InterruptedException {
           TestThread thread1=new     TestThread("https://www.baidu.com/img/dong_47f08bb2dd6546c9a788f71d7463ce48.gif","1.jpg");
           TestThread thread2=new TestThread("https://www.baidu.com/img/flexible/logo/pc/result.png","2.jpg");
           TestThread thread3=new TestThread("https://pic.rmb.bdstatic.com/bjh/user/0adaa3b9ae82034d4cbd913b354610a3.jpeg?x-bce-process=image/resize,m_lfit,w_200,h_200&autime=14","3.jpg");

           //创建执行服务;
           ExecutorService executorService = Executors.newFixedThreadPool(3);
           //提交执行
           Future<Boolean> future1 = executorService.submit(thread1);
           Future<Boolean> future2 = executorService.submit(thread2);
           Future<Boolean> future3 = executorService.submit(thread3);

           //获取结果
           boolean rs1 = future1.get();
           boolean rs2 = future2.get();
           boolean rs3 = future3.get();
           System.out.println(rs1);
           System.out.println(rs2);
           System.out.println(rs3);

           //关闭服务
           executorService.shutdown();



      }
    }

    //定义下载器
    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的异常信息"+e);
          }
      }

    }

4.静态代理模式(多线程底部实现的方式)

 //代理模式总结:
  //真实对象和代理对象都要实现同一个接口
  //代理对象要代理真实角色

  //好处:
      //代理对象可以做很多真实对象做不了的事情
      //真实对象专注做自己的事情
  public static void main(String[] args) {

      //线程的底部实现原理也是这种静态代理模式
      new Thread(()-> System.out.println("我宣你")).start();
      new WeddingCompany(new You()).HarryMarry();
  }
}

//定义一个接口
interface Marry {
  //接口中的方法只有定义
  void HarryMarry();
}

//定义一个内部类,实现Marry接口
class You implements Marry {
  //实现接口之后,就要重写方法
  @Override
  public void HarryMarry() {
      System.out.println("我要结婚了!!!");
  }
}


//代理的解决,帮助你结婚
class WeddingCompany implements Marry {

  private Marry target;

  public WeddingCompany(Marry target) {
      this.target = target;
  }

  @Override
  public void HarryMarry() {
      before();
      this.target.HarryMarry();
      after();
  }

  public void before() {
      System.out.println("执行前需要做的方法");
  }

  public void after() {
      System.out.println("执行后需要做的方法");
  }
  1. Lamda表达式

/**
* @Lamda表达式
*/
public class StaticProxy {

   //3.静态内部实现类
   static class Like2 implements ILike{
       @Override
       public void Lamda() {
           System.out.println("I LIKE LAMDA2");
      }
  }

   public static void main(String[] args) {
       ILike like = new Like();
       like.Lamda();

       like = new Like2();
       like.Lamda();

       //4.局部内部类
       class Like3 implements ILike{
           @Override
           public void Lamda() {
               System.out.println("I LIKE LAMDA3");
          }
      }
       like = new Like3();
       like.Lamda();

       //5.匿名内部类 没有类的名称 必须借助接口或者父类
       like = new ILike() {
           @Override
           public void Lamda() {
               System.out.println("I LIKE LAMDA4");
          }
      };
       like.Lamda();
       //6.用lamda简化
       like = ()->{
           System.out.println("I LIKE LAMDA5");
      };
       like.Lamda();
       //7.lamda本身代码简化
       like = ()->System.out.println("I LIKE LAMDA5");;
       like.Lamda();
       //总结:
       //lamada表达式只能有一行代码的情况下才能简化成为一行,如果有多行,那么就用代码块{}包裹住
       //前提是接口为函数式接口:只能有一个方法
       //一个参数可以将()省略,也可以将参数类型去掉
       //多个参数也可以去掉参数类型,要去掉就都去掉,必须加上括号
  }
}


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

//2.实现类
class Like implements ILike{
   @Override
   public void Lamda() {
       System.out.println("I LIKE LAMDA1");
  }
}
  1. 线程停止

//测试stop
   //1.建议线程正常停止-->利用次数,不建议死循环
   //2.建议使用标志位---->设置一个标志位
   //3.不要使用stop或者destory等过时或者JDK不建议使用的方法
public class StaticProxy 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) {
       StaticProxy staticProxy = new StaticProxy();
       new Thread(staticProxy).start();
       for (int i = 0; i < 1000; i++) {
           System.out.println("主线程main"+i);
           if(i==900){
               //调用线程停止的方法
               staticProxy.stop();
               System.out.println("线程该停止了");
          }
      }
  }
}
  1. sleep休眠

public static void main(String[] args) {
   //打印系统当前时间
   Date date = new Date(System.currentTimeMillis());
   while (true){
       try {
           Thread.sleep(1000);
      } catch (InterruptedException e) {
           e.printStackTrace();
      }
       System.out.println(new SimpleDateFormat("HH:mm:ss").format(date));
       date = new Date(System.currentTimeMillis());
  }
}
//模拟倒计时
public static void tenDown() throws InterruptedException {
   int i=10;
   while (true){
       Thread.sleep(1000);
       System.out.println(i--);
       if(i<=0){
           break;
      }
  }
}
  1. 礼让线程(yield)

    //测试礼让线程
   //礼让不一定成功,看CPU心情

public class StaticProxy {
   public static void main(String[] args) {
       MyYiled myYiled1 = new MyYiled();
       MyYiled myYiled2 = new MyYiled();
       new Thread(myYiled1).start();
       new Thread(myYiled2).start();
  }
}
class MyYiled implements Runnable{
   @Override
   public void run() {
       System.out.println(Thread.currentThread().getName()+"线程开始");
       Thread.yield();
       System.out.println(Thread.currentThread().getName()+"线程结束");
  }
}
  1. 强制执行(join)

public class StaticProxy   {
   public static void main(String[] args) throws InterruptedException {

       MyJoined myJoined = new MyJoined();
       Thread thread = new Thread(myJoined);
       thread.start();

       for (int i = 0; i < 500; i++) {
           if(i==200){
               thread.join();
          }
           System.out.println("主线程mian"+i);
      }
  }
}
class MyJoined implements Runnable{
   @Override
   public void run() {
       for (int i = 0; i < 1000; i++) {
           try {
               Thread.sleep(10);
          } catch (InterruptedException e) {
               e.printStackTrace();
          }
           System.out.println("VIP线程进来了"+i);
      }
  }
}
  1. 线程的状态

{
       //观测线程的状态
       Thread t  = new Thread(()->{
           for (int i = 0; i < 5; i++) {
               try {
                   Thread.sleep(1000);
              } catch (InterruptedException e) {
                   e.printStackTrace();
              }
          }
           System.out.println("线程运行结束");
      });

       //观察状态
       Thread.State state = t.getState();
       System.out.println(state);  //NEW

       //观察启动后
       t.start();//启动线程
       state = t.getState();
       System.out.println(state);  //run

       while(state != Thread.State.TERMINATED){
           //只要线程不终止,就一直输出状态
           Thread.sleep(100);
           state = t.getState();//更新线程状态
           System.out.println(state); //输出状态
      }
       //死亡之后的线程就不能在运行了 t.start()就会报错

}
  1. 线程优先级

   public static void main(String[] args) throws InterruptedException {
       //测试线程的优先级
       //主程序默认优先级
       System.out.println(Thread.currentThread().getName()+"--->"+Thread.currentThread().getPriority());
       MyPriority myPriority = new MyPriority();

       Thread thread1 = new Thread(myPriority,"线程1");
       Thread thread2 = new Thread(myPriority,"线程2");
       Thread thread3 = new Thread(myPriority,"线程3");
       Thread thread4 = new Thread(myPriority,"线程4");
       Thread thread5 = new Thread(myPriority,"线程5");
       Thread thread6 = new Thread(myPriority,"线程6");

       //先设置优先级,在进行启动
       thread1.start();

       thread2.setPriority(1);
       thread2.start();

       thread3.setPriority(4);
       thread3.start();

       thread4.setPriority(Thread.MAX_PRIORITY);//设置最大值等于10
       thread4.start();
       
       //最最小值为1,最大值为10,如果超过其范围,则会报错
//       thread5.setPriority(-1);
//       thread5.start();
//       thread6.setPriority(11);
//       thread6.start();


  }
}



class MyPriority implements Runnable{

   @Override
   public void run() {
       System.out.println(Thread.currentThread().getName()+"--->"+Thread.currentThread().getPriority());

  }
}
  1. 守护线程

public class StaticProxy   {
   public static void main(String[] args) throws InterruptedException {
       //守护线程
       God god = new God();
       You you = new You();

       Thread thread = new Thread(god);
       thread.setDaemon(true);  //默认是false,表示的是用户线程,正常的线程都是用户线程
       thread.start();//上帝守护线程启动

       new Thread(you).start();//用户线程启动。。


  }
}

class God implements Runnable{
   @Override
   public void run() {
      while(true){
          System.out.println("上帝一直保佑的你!!!");
      }
  }
}

class You implements Runnable{
   @Override
   public void run() {
       for (int i = 0; i < 36500; i++) {
           System.out.println("看到的人你一生都开心的活着!!!");
      }
       System.out.println("===================羽化成仙,直接飞升=============");
  }
}

 

  1. 三大不安全线程案例

(1. 火车买票已经在上述代码中) (2.银行取钱) (3.arrayList线程不安全)

/**
* 不安全的银行取钱
*/
public class StaticProxy   {
  public static void main(String[] args) throws InterruptedException {
      //账户
      Account account = new Account(100,"游戏基金");
      Drawing drawingBoy = new Drawing(account,50,"男朋友");
      Drawing drawingGirl = new Drawing(account,100,"女朋友");
      drawingBoy.start();
      drawingGirl.start();

  }
}

//定义银行账户
class Account{
  int money;//余额
  String name;//卡名

  public Account(int money, String name) {
      this.money = money;
      this.name = name;
  }
}

//定义去银行取钱的线程操作
class Drawing extends Thread{
  Account account;//账户
  //取了多少钱
  int drawingMoney;
  //目前手中的钱数
  int nowMoney;

  public Drawing(Account account, int drawingMoney, String name) {
      super(name);
      this.account = account;
      this.drawingMoney = drawingMoney;
  }

  @Override
  public void run(){
      //自己去银行取钱
      if(account.money-drawingMoney<0){
          System.out.println(Thread.currentThread().getName()+"钱不够,取不了钱");
          return;
      }
      try {
          Thread.sleep(100);
      } catch (InterruptedException e) {
          e.printStackTrace();
      }
      //卡内余额 = 余额 - 取得钱数
      account.money = account.money - drawingMoney;
      //手中的钱数
      nowMoney = nowMoney + drawingMoney;
      System.out.println(account.name+"卡内的余额为:"+account.money);
      //Thread.currentThread().getName()等价于this.getName()
      System.out.println(this.getName()+"手中的钱"+nowMoney);
  }
}
**
* 线程不安全的集合
*/
public class StaticProxy {
   public static void main(String[] args) throws InterruptedException {
       List<String> arrayList = new ArrayList<String>();
       for (int i = 0; i < 10000; i++) {
           new Thread(()->{
               arrayList.add(Thread.currentThread().getName());
          }).start();
      }
       System.out.println(arrayList.size());
  }
}
  1. 如何保证线程的安全性【锁的对象一定要是变化的量,就是需要增删改的对象】

synchronized锁方法 默认锁的是this这个对象 加在方法上 public synchronized

synchronized块 synchronized(任何需要被锁的队形){}

public static void main(String[] args) throws InterruptedException {
   List<String> arrayList = new ArrayList<String>();
   for (int i = 0; i < 10000; i++) {
       new Thread(()->{
           synchronized (arrayList){
               arrayList.add(Thread.currentThread().getName());
          }
      }).start();
  }
   Thread.sleep(1000);
   System.out.println(arrayList.size());
}
  1. CopyOnWriteArrayList     属于JUC   java.util.concurrent  线程安全的集合
  1. 死锁产生的原因

//死锁:多个线程互相抱着对方需要的资源,然后形成僵持
public class StaticProxy {
   public static void main(String[] args) throws InterruptedException {
       MakeUp makeUp1 = new MakeUp(1,"明明");
       MakeUp makeUp2 = new MakeUp(2,"红红");
       makeUp1.start();
       makeUp2.start();
  }
}
//口红类
class LipsTick {
}
//镜子类
class Mirror {
}
class MakeUp extends Thread {

   //需要的资源只需要一份,用static来保证只有一份
   static LipsTick  lipsTick = new LipsTick();
   static Mirror mirror = new Mirror();

   int chooice;
   String personname;

   public MakeUp(int chooice, String personname) {
       this.chooice = chooice;
       this.personname = personname;
  }

   @Override
   public void run() {
       try {
           makeup(chooice,personname);
      } catch (InterruptedException e) {
           e.printStackTrace();
      } {}
  }

   //化妆的方法
   public void makeup(int chooice, String personname) throws InterruptedException {
       if (chooice==1){
           synchronized (lipsTick){
               System.out.println(personname+"已经拿到了口红的锁");
               Thread.sleep(100);
          }
           synchronized (mirror){
               System.out.println(personname+"我已经拿到了镜子的锁");
          }
      }else{
           synchronized (mirror){
               System.out.println(personname+"已经拿到了镜子的锁");
               Thread.sleep(200);
          }
           synchronized (lipsTick){
               System.out.println(personname+"已经拿到了口红的锁");
          }
      }
  }
}
  1. Lock锁

//测试lock锁
public class StaticProxy {
   public static void main(String[] args) throws InterruptedException {

       BuyTicket buyTicket = new BuyTicket();

       new Thread(buyTicket).start();
       new Thread(buyTicket).start();
       new Thread(buyTicket).start();
  }
}
class BuyTicket implements Runnable {
   int ticket = 10;
   //定义lock锁
   private final ReentrantLock lock = new ReentrantLock();

   @Override
   public void run() {
       while (true) {
           try {
               lock.lock();
               if (ticket > 0) {
                   try {
                       Thread.sleep(1000);
                  } catch (InterruptedException e) {
                       e.printStackTrace();
                  }
                   System.out.println(ticket--);
              } else {
                   break;
              }
          } finally {
               lock.unlock();
          }
      }
  }
}
  1. 生产者消费者问题

//测试:生产者消费者模型-->利用缓冲区解决:管程法
//生产者,消费者,缓冲区,产品
public class StaticProxy {
   public static void main(String[] args) throws InterruptedException {
       SynContainer synContainer = new SynContainer();
       Productor productor = new Productor(synContainer);
       Consutmer consutmer = new Consutmer(synContainer);
       productor.start();
       consutmer.start();
  }
}


//生产者
class Productor extends Thread{
   //生产者只做生产鸡的操作
   SynContainer synContainer;

   public Productor(SynContainer synContainer) {
       this.synContainer = synContainer;
  }

   @Override
   public void run(){
       //生产鸡的操作
       for (int i = 0; i < 100; i++) {
           synContainer.productChicken(new Chicken(i));
           System.out.println("当前生产了第"+i+"只鸡!!!");
      }
  }
}

//消费者
class Consutmer extends Thread{
   //消费者只做消费鸡的操作
   SynContainer synContainer;

   public Consutmer(SynContainer synContainer) {
       this.synContainer = synContainer;
  }

   @Override
   public void run(){
       //消费鸡的操作
       for (int i = 0; i < 100; i++) {
           System.out.println("当前消费了第"+synContainer.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 productChicken(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;
  }


}
  1. 标志位方法其实就是另一种程度的管程法

  1. 线程池

//测试线程池
public class StaticProxy {
   public static void main(String[] args) throws InterruptedException {

       //1.创建服务,创建线程池
       //newFixedThreadPool   参数为:线程池大小
       ExecutorService service = Executors.newFixedThreadPool(10);

       //执行了线程池的方法,没有返回值
       service.execute(new MyThread());
       service.execute(new MyThread());
       service.execute(new MyThread());
       service.execute(new MyThread());

       //关闭连接
       service.shutdown();
  }
}

class MyThread implements Runnable{

   @Override
   public void run() {
       for (int i = 0; i < 100; i++) {
           System.out.println(Thread.currentThread().getName());
      }
  }
}
posted @ 2021-03-27 14:39  HOTCOLD  阅读(156)  评论(0)    收藏  举报