多线程详解

#多线程详解

线程,进程

什么是进程?

开发写的代码称为程序,那么我们将程序运行起来,我们称之为进程;当我们运行一个程序,那么我们将运行的程序叫进程;进程就是申请一块内存空间,将数据放到内存空间中去,是申请数据的过程中最小的资源管理单元;进程是线程的容器;

程序与进程的区别

程序是数据和指令的集合,是一个静态的概念,就是一堆代码,可以长时间的保存在系统中;

进程是程序运行的过程,是一个动态的概念,进程存在着生命周期,也就是说进程会随着程序的终止而销毁,不会永久存在系统中;

进程间的交互

进程之间通过 TCP/IP 端口实现的

什么是线程?

01.线程是操作系统能够进行运算调度的最小单位;
02.被包含在进程之中,是进程中的实际运作单位;
03.一个线程指进程中一个单一顺序的控制流,一个进程可以并发多个线程,每条线程并行执行不同的任务;
04.是进程的一条流水线,只用来执行程序,而不涉及到申请资源,是程序的实际执行者,是最小的执行单位;


线程之间的交互

多个线程共享同一内存,通过共享的内存空间来交互

举例说明,进程和线程的关系

比如说我们用手机打开微信,运行的微信就是开启的一个线程,当我们使用微信的一些功能,扫一扫,付款等,这些都是线程;
进程包含线程,线程属于进程的子集;

进程池

进程池是资源进程,管理进程组成的应用及技术;

为什么要有进程池?

😮忙时会有成千上万的任务需要被执行,闲时可能只有零星任务。
😒那么在成千上万个任务需要被执行的时候,我们就需要去创建成千上万个进程么?
😓首先,创建进程需要消耗时间,销毁进程也需要消耗时间。
😟第二即便开启了成千上万的进程,操作系统也不能让他们同时执行,这样反而会影响程序的效率。
😥因此我们不能无限制的根据任务去开启或者结束进程。那么我们要怎么做呢?

进程池的概念

1.定义一个池子,里面放固定数量的进程,有需求来了,就从池子里拿一个进程来处理任务;
2.任务处理完毕,进程并不关闭,而是将进程放回池子中等待任务;
3.如果有很多任务要执行,池子中进程数量不够,任务就要等待进程执行完之后,拿到空闲的进程才能执行;
4.池子中进程数量是固定的,也就是说同一时间最多能执行固定经常的任务
5.这样不会增加操作系统的调度难度,还节省了开关进程的时间,也能在一定程度上实现并发效果;

资源进程

预先创建好空的进程,管理进程会把任务分发到空闲进程来处理

管理进程

管理进程负责创建资源进程,把工作交给空闲资源处理,回收已经处理完的资源进程;

资源进程与管理进程的交互

管理进程如何有效的管理资源进程,分配任务给资源进程?

通过 IPC,信号,信号量,消息队列,管道等进行交互。

并发、并行和串行

并发:多个任务看起来同时执行,这是一种假并行;

单核下使用多道技术实现;

并行:多个任务同时进行

并行必须有多核才能实现,否则只能实现并发

串行:一个程序处理完当前进程,接着处理下一个进程,一个一个连着进行

进程的三态

进程在运行的过程中不断的改变其运行状态;

通常一个运行的进程必须要有三个状态,就绪态,运行态,阻塞态

1. 就绪态
当进程获取除 CPU 外所有的资源后,只要在获得 CUP 就可执行程序,这时的状态叫做就绪态;

在一个系统中处于就绪态的进程会有多个,通常把这些排成一个队列,这个就叫就绪队列;

2. 运行态
当进程已经获得 CPU 操作权限,正在运行,这个时间就是运行态

在单核系统中,同一个时间只能有一个运行态,多核系统中,会有多个运行态;

3. 阻塞态
正在执行的进程,等待某个事件而无法继续运行时,便**作系统剥夺了 cpu 操作权限,这时时阻塞态;

引起阻塞的原因有很多,等待 I/O 操作,被更高优先级的进程剥夺了 cpu 权限等;

线程的方法


方法说明
setPriority (int newPriority)更改线程的优先级
sleep (long millis)制定毫秒数,让当前运行的线程休眠
join ()等待该线程的终止
yield ()暂停当前正在执行的线程对象,并执行其他的线程
interrupt ()中断线程
isAlive线程是否在活跃状态

Java 使用多线程

创建线程的三种方式

继承 Thread 类
public class MyThread extends Thread implements Runnable {  
     @Override  
     public void run() {  
     for (int i = 0; i < 100; i++) {  
         System.out.println("继承Thread实现了第"+i+"次调用;");  
        }  
     }
 }
/**  
 * 继承thread 实现多线程  
 * 1. 类继承Thread  
 * 2. 重写run()  
 * 3. start() 调用  
 */  
@Test  
public void extendThreadTest(){  
 MyThread myThread = new MyThread();  
    myThread.start();  
    int ii = 20;  
    for (int i = 0; i < ii ; i++) {  
 System.out.println("main调用了"+i+"次;");  
    }  
}
实现 Runable 接口
public class MyRunnable implements Runnable{  
     @Override  
     public void run() {  
     for (int i = 0; i < 100; i++) {  
         System.out.println("实现Runnable实现了第"+i+"调用;");  
        }  
     }
}
/**  
 * 实现Runnable接口实现多线程  
 * 1. 类实现Runnable  
 * 2. 重写run()  
 * 3. start() 调用  
 */  
@Test  
public void implementsRunnableTest(){  
     MyRunnable myRunnable = new MyRunnable();  
        new Thread(myRunnable).start();  
        for (int i = 0; i < 20; i++) {  
             System.out.println("main调用了"+i+"次;");  
        }  
}
实现 Callable 接口
实现 Callable 接口, 需要返回值
重写 call 方法,需要抛出异常
创建目标对象
创建执行服务,: ExecutorService service = Executors.newCachedThreadPool();
提交执行:提交执行:Future<> submit = service. Submit (对象);
获取结果 :Boolean aBoolean = submit. Get ();
关闭服务:service. ShutdownNow ();
public class MyCallable implements Callable<Boolean> {  
     @Override  
     public Boolean call() throws Exception {  
         return false;  
     }  
}
@Test  
public  void implementCallableTest() throws ExecutionException, InterruptedException {  
    MyCallable myCallable = new MyCallable();  
    ExecutorService service = Executors.newCachedThreadPool();  
    Future<Boolean> submit = service.submit(myCallable);  
    Boolean aBoolean = submit.get();  
    service.shutdownNow();  
}

线程的状态

New
线程已创建,尚未启动
Runnable
在 Java 虚拟机中正在执行的线程
Blocked
被等待监视器锁定的线程
Waiting
正在等待另一个线程执行特定动作的线程处于此状态
Timed_waiting
正在等待另一个线程执行动作达到指定等待时间的线程处于此状态
Terminated
已退出的线程
/**  
 * @ClassName: MyThreadState  
 * @Description: 观察线程的状态  
 * 通过state方法可以观察线程的状态  
 */
public class MyThreadState implements Runnable {  
     @Override  
     public void run() {  
         for (int i = 0; i < 10; i++) {  
             if(i==5 && i<10){  
                 try {  
                     Thread.sleep(1);  
                     System.out.println("阻塞时的状态"+Thread.currentThread().getState());  
                 } catch (InterruptedException e) {  
                     e.printStackTrace();  
                  }  
             } 
             System.out.println(Thread.currentThread().getName()+i+"线程正在执行的状态:"+Thread.currentThread().getState());  
         }  
     }
}
public static void main(String[] args) {  
    
 MyThreadState myThreadState = new MyThreadState();  
    Thread thread = new Thread(myThreadState);  
    
    Thread.State state = thread.getState();  
    System.out.println("线程创建未启动时状态:"+state); 
    
    thread.start();  
    state = thread.getState();  
    System.out.println("线程启动后的状态:"+state);  
    
    while (thread.getState()!= Thread.State.TERMINATED){  
        state = thread.getState();  
        System.out.println(thread.getName()+"线程运行时状态:"+state);  
    }  
    state = thread.getState();  
    System.out.println("线程结束状态:"+state);  
    System.out.println(Thread.currentThread().getName()+"线程优先级"+Thread.currentThread().getPriority());  
}

线程停止

建议线程正常停止; -> 一般是利用次数
建议使用标志位;
不建议使用 stop 和 destroy 方法,已过时
public class MyThreadStop implements Runnable {  
     /**标识位判断线程是否停止*/  
     private boolean flag = true;  
     @Override  
     public void run() {  
         int i =0;  
         while (flag){  
             System.out.println(Thread.currentThread().getName()+""+i++);  
         }  
     }  
     /**设置一个公开的方法停止线程*/  
     public  void stopThread(boolean flag){  
         this.flag=flag;  
     }
}
public static void main(String[] args) {  
     MyThreadStop myThreadStop = new MyThreadStop();  
        Thread thread = new Thread(myThreadStop);  
        thread.start();  
        for (int i = 0; i < 1000; i++) {  
        if(i==200){  
             myThreadStop.stopThread(false);  
         }  
        System.out.println(Thread.currentThread().getName()+"执行"+i);  
     }  
}

线程的优先执行

Join 主要作用是优先执行
/**  
 * @ClassName: MyThreaJoin  
 * @Description: join 主要作用是优先执行  
 */
public class MyThreaJoin implements Runnable {  
     @Override  
     public void run() {  
     for (int i = 0; i < 20; i++) {  
     System.out.println(Thread.currentThread().getName()+"vip线程开始跑!"+i);  
            }  
     }
 }
public static void main(String[] args) {  
     //启动线程  
     MyThreaJoin threaJoin = new MyThreaJoin();  
     Thread thread = new Thread(threaJoin);  
     thread.start();  
     for (int i = 0; i < 20; i++) {  
         if(i==10){  
             try {  
                 thread.join();  
             } catch (InterruptedException e) {  
                 e.printStackTrace();  
             }  
         } 
     System.out.println(Thread.currentThread().getName()+i+"正在跑!");  
    }  
}

线程的优先级

SetPriority (int i ) 设置线程优先级
GetPriority () 获取线程的优先级
class TestPriority extends Thread{  
     @Override  
     public void run() {  
     System.out.println(TestPriority.currentThread().getName()+"的优先级"+TestPriority.currentThread().getPriority());  
     }  
}
public class MyThreadPriority {  
     public static void main(String[] args) {  
        TestPriority priority1 = new TestPriority();  
        TestPriority priority2 = new TestPriority();  
        TestPriority priority3 = new TestPriority();  
        TestPriority priority4 = new TestPriority();  
        TestPriority priority5 = new TestPriority();  
        System.out.println(Thread.currentThread().getName()+"线程优先级"+Thread.currentThread().getPriority());  
        priority1.setPriority(6);  
        priority1.start();  
//        System.out.println("priority1"+priority1.getPriority());  
        priority2.setPriority(2);  
        priority2.start();  
//        System.out.println("priority2"+priority2.getPriority());  
        priority3.setPriority(3);  
        priority3.start();  
//        System.out.println("priority3"+priority3.getPriority());  
        priority4.setPriority(8);  
        priority4.start();  
//        System.out.println("priority4"+priority4.getPriority());  
        priority5.setPriority(5);  
        priority5.start();  
//        System.out.println("priority5"+priority5.getPriority());  
     }  
}

守护线程

线程分为用户线程和守护线程\
虚拟机必须确保用户线程执行完\
虚拟机不必等待守护线程执行完毕\
如:后台记录日志,监控内存,垃圾回收线程等
/**  
 * 上帝,守护线程  
 */  
class God implements Runnable{  
     @Override  
     public void run() {  
         long l = 0;
         while (true){  
             out.println("上帝保佑你!"+l++);  
         }  
     }
}
/**  
 * you 用户线程  
 */  
class You implements Runnable{  
     @Override  
     public void run() {  
         for (int i = 0; i < 35000; i++) {  
             out.println("每天都在健康的活着"+i);  
         }  
         out.println("you goodBye world!");  
     }  
}
/**
* 启动用户线程和守护线程
*/
public class MyThreadDaemon {  
     public static void main(String[] args) {  
        You you = new You();  
        God god = new God();  
        Thread youThread = new Thread(you);  
        Thread godThread = new Thread(god);  
        godThread.setDaemon(true);  
        youThread.start();  
        godThread.start();  
     }  
}

Synchronized 方法

Sybchronized 方法控制对对象的访问,每个对象对应一把锁,每个 synchronized 方法都必须获取调用方法的对象的锁才能执行,否则线程会阻塞,方法一旦执行,就独占该锁,知道方法返回才释放锁,后面被阻塞的线程才能获得锁,继续执行;
若将一个大的方法申明为 synchronized 将会影响概率
同步代码块:synchronized(obj){}

Obj 称之为同步监视器

obj 可以是任何对象,但是推荐使用共享资源作为同步监视器
同步方法中无需指定同步监视器,因为同步方法的同步监视器就是 this,这个对象本身;

同步监视器的执行过程

01.第一个线程访问,锁定同步监视器,执行其中的代码
02.第二个线程访问,发现同步监视器被锁定,无法访问
03.第一个线程访问完毕,解锁同步监视器
04.第二个线程访问,发现同步监视器没有锁,然后锁定并访问;
多人购票的问题
 class BuyTicket implements Runnable{  
     //票数  
     private int ticketNums= 10;  
        //外部停止方式  
         boolean flag = true;  
         @Override  
         public void run() {  
         while (flag){  
             try {  
                 buy();  
                } catch (InterruptedException e) {  
                     e.printStackTrace();  
                }  
             } } 
         private synchronized void buy() throws InterruptedException {  
             Thread.sleep(100);  
             //判断是否有票  
             if(ticketNums<=0){  
                 flag=false;  
                 return;  
             }  
             System.out.println(Thread.currentThread().getName()+"买到了第"+ticketNums--+"张票;");  
        }  
}
/**  
 * @ClassName: MyThreadSyn  
 * @Description: 线程同步的问题-多人购票   
 */
public class MyThreadSyn1 {  
     public static void main(String[] args) {  
         BuyTicket buyTicket1 = new BuyTicket();  
            Thread you = new Thread(buyTicket1, "you");  
            Thread me = new Thread(buyTicket1, "me");  
            Thread other = new Thread(buyTicket1, "other");  
            you.start();  
            me.start();  
            other.start();  
        }  
}
银行取钱问题
  1. 创建账户信息

    @Data  
    @AllArgsConstructor  
    class Account {  
         /**余额*/  
         private int money;  
            /**卡名*/  
         private String name;  
    }
    
  2. 模拟银行取钱

    /**  
     * 模拟银行取钱  
     */  
    class Drawing extends Thread{  
         private final Account account;  
         /**现有的钱*/  
         private  int nowMoney;  
         /**取出的钱*/  
         private int drawingMoney;  
         public Drawing( Account account,  int drawingMoney,String name) {  
             super(name);  
             this.account = account;  
             this.drawingMoney = drawingMoney;  
            }  
         @Override  
         public void run() {  
             synchronized (account){  
             //判断有没有钱  
             if(account.getMoney()-drawingMoney<0){  
                 out.println("你的账户没有那么多钱!");  
                 return;  
             }try {  
                 sleep(100);  
             } catch (InterruptedException e) {  
                 e.printStackTrace();  
             }  
             //余额  
             account.setMoney( account.getMoney() - drawingMoney);  
             //手中的钱  
             nowMoney=nowMoney+drawingMoney;  
             out.println("余额为:"+account.getMoney());  
             out.println(Thread.currentThread().getName()+"手中的钱:"+nowMoney);  
            }  
         }
    }
    
  3. 测试取钱流程

    /**  
     * @ClassName: MyThreadSyn2  
     * @Description: 线程同步的问题-多人从银行取钱  
     */
    public class MyThreadSyn2 {  
     public static void main(String[] args) {  
         Account account = new Account(100, "工商");  
         Drawing me = new Drawing(account, 40, "me");  
         Drawing girlFriend = new Drawing(account, 89, "girlFriend");  
         me.start();  
         girlFriend.start();  
        }  
    }
    
ArrayList 线程不安全
/**  
 * @ClassName: MyThreadSyn  
 * @Description: 线程同步的问题-ArrayList线程不安全  
 */
public class MyThreadSyn3 {  
     public static void main(String[] args) {  
         ArrayList<String> arrayList = new ArrayList<>();  
            for (int i = 0; i < 10000; i++) {  
                 new Thread(()-> {  
                 synchronized(arrayList){  
                 arrayList.add(Thread.currentThread().getName());  
                                }  
                 }).start();  
            }  
         try {  
             Thread.sleep(100);  
         } catch (InterruptedException e) {  
             e.printStackTrace();  
         }  
         out.println(arrayList.size());  
    }  
}
注意: 如果将线程等待去掉,还是会有线程不安全,暂不明白其原理,待后续搞明白

死锁

多个线程各自占有一些共享资源,并且相互等待其他线程占用的资源才能运行,而导致两个或两个以上的线程都在等待对方释放资源,都停止执行的情形;某一个同步块同时拥有两个对象以上的锁,就有可能发生死锁

产生死锁的必要条件

互斥条件:一个线程只能被一个人使用
请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放
不剥夺条件: 进程以获得的资源,在未使用完之前,不能剥夺;
循环等待条件:若干进程之间形成一种头尾相接的循环等待资源的关系

实现一个死锁

/**  
 * 口红  
 */  
class Lipstick{  
}  
/**  
 * 镜子  
 */  
class Mirroe{  
}
/**  
 * 写一个抢夺资源的方法  
 */  
class Makeup extends Thread{  
    static Lipstick lipstick = new Lipstick();  
    static Mirroe mirroe = new Mirroe();  
    int choice;  
    String girlName;  
    public Makeup(int choice, String girlName) {  
        this.choice = choice;  
        this.girlName = girlName;  
    }  
     @Override  
     public void run() {  
         try {  
             makeup();  
         } catch (InterruptedException e) {  
             e.printStackTrace();  
         }  
     }  
     public void makeup() throws InterruptedException {  
         if(choice==0){  
             synchronized (lipstick){  
                 System.out.println(this.girlName+"获取口红的锁");  
                 Thread.sleep(1000);  
                 synchronized (mirroe){  
                     System.out.println(this.girlName+"获取镜子的锁");  
                 }  
             } 
         }else{  
             synchronized (mirroe){  
                 System.out.println(this.girlName+"获取镜子的锁");  
                 Thread.sleep(1000);  
                 synchronized (lipstick){  
                     System.out.println(this.girlName+"获取口红的锁");  
                 }  
             } 
         } 
     }
}
Lock
Java 提供了更强大的线程同步机制—通过显式定义同步锁对象来实现同步;同步锁使用 Lock 对象充当;
Lock 接口时控制多个线程对共享资源进行访问的工具。锁提供了对共享资源的独占访问,每次只能有一个线程对 Lock 对象加锁,线程开始访问共享资源之前应先获得 Lokc 对象;
ReentrantLock 类实现了 Lock, 他拥有 synchronized 相同的并发性和内存语义,在实现线程安全的控制中,比较常用的时 ReentrantLock,可以显示枷锁释放锁;
/**  
 * 多人买票,用lock的方式实现  
 */  
class TestLock2 implements Runnable{  
    int ticketNums=10;  
    private final ReentrantLock lock = new ReentrantLock();  
     @Override  
     public void run() {  
         while (true){  
             lock.lock();  
             try {  
                 if(ticketNums>0){  
                     try {  
                         Thread.sleep(100);  
                      } catch (InterruptedException e) {  
                         e.printStackTrace();  
                      }  
                 System.out.println(Thread.currentThread().getName()+"买到了票"+ticketNums--);  
                  }else {  
                     break;  
                  }  
              }finally {  
                  lock.unlock();  
              }  
         } 
     }
}
public class TestLock {  
    public static void main(String[] args) {  
        TestLock2 testLock2 = new TestLock2();  
        new Thread(testLock2,"you").start();  
        new Thread(testLock2,"me").start();  
        new Thread(testLock2,"other").start();  
    }  
}

线程通信

方法名作用
wait ()表示线程一直等待,直到其他线程通知,与 sleep 不同会释放锁
wait (long timeOut)指定等待的毫秒数
notify ()唤醒一个处于等待状态的线程
notifyAll()唤醒同一个对象所有的调用 wait()方法的线程,优先级高的优先调度
线程通讯,生产消费模式-管程法
/**  
 * 产品-鸡  
 */  
@AllArgsConstructor  
class Chicken{  
     int id;  
}
/**  
 * 生产者  
 */  
class Productor extends Thread{  
     SynContainer container;  
     public Productor(SynContainer container){  
         this.container=container;  
     }  
     @Override  
     public void run() {  
         for (int i = 0; i < 100; i++) {  
             container.pushTo(new Chicken(i));  
             System.out.println("生产了"+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.popTo().id+"只鸡");  
         }  
     }
}
class SynContainer{  
     /**定义一个容器的大小*/  
     Chicken[] chickens = new Chicken[10];  
     /** 容器计数器*/  
     int count;  
     /**  
     * 生产者想容器中放入产品  
     * @param chicken  
     */  
     public synchronized  void pushTo(Chicken chicken){  
         //如果容器满了,就需要等待消费者消费  
         if(chickens.length==count){  
             //通知消费者消费  
             try {  
                 this.wait();  
                 } 
             catch (InterruptedException e) {  
                 e.printStackTrace();  
             }  
          } 
          //如果没有满就丢入产品  
          chickens[count]=chicken;  
          count++;  
          //通知消费者消费  
          this.notifyAll();  
     }  
     /**  
     * 消费者从中取出产品  
     * @return  
     */  
     public synchronized Chicken popTo(){  
         //判断能否消费  
         if(count==0){  
             // 消费者等待生产者产出  
             try {  
                 this.wait();  
                  } catch (InterruptedException e) {  
                     e.printStackTrace();  
              }  
         } 
         //如果可以消费  
         count--;  
         Chicken chicken = chickens[count];  
         //吃完了通知生产者消费  
         this.notifyAll();  
         return chicken;  
    }  
}
线程通讯,生产消费模式-信号灯法

代理模式

  1. 不属于23种设计模式之一,只是在代码种使用的模式
    
    1. 创建一个公共接口;
    2. 一个真实的类,实现公告接口
    3. 一个代理类实现公共接口,代理类中要有真实的类的属性
    4. 通过代理类,实现真实类的方法
    
/**  
* 结婚接口  
*/  
interface Marry{  
  /**  
   * 实现结婚的方法  
   */  
   void happenMarry();  
}
/**
真实角色
*/
class Men implements Marry{
private String name;
 public Men(String name) {  
     this.name = name;  
 }  
 @Override  
 public void happenMarry() {  
     System.out.println(this.name+ "结婚");  
 }
 }
/**  
 * 婚庆公司  
 */  
class WeddingCompany implements Marry{  
     private Marry target;  
     public WeddingCompany(Marry target) {  
        this.target = target;  
     }  
     @Override  
     public void happenMarry() {  
         before();  
         this.target.happenMarry();  
         after();  
     }  
     private void after() {  
         System.out.println("婚礼结束,准备收钱!");  
     }  
     private void before() {  
         System.out.println("婚礼准备中!");  
     }  
  }
public class DynamicProxy {  
 public static void main(String[] args) {  
     Marry sun = new Men("sun");  
     WeddingCompany weddingCompany = new WeddingCompany(sun);  
     weddingCompany.happenMarry();  
 }  
}

多线程例子

多图片下载

/**  
 * @ClassName: WebDownLoader  
 * @Description: 使用commas 类中的数据进行图片下载  
 */
public class WebDownLoader {  
     public void downLoader(String filaUrl,String fileName){  
         try {  
             FileUtils.copyURLToFile(new URL(filaUrl), new File(fileName));  
             System.out.println("成功执行了方法");  
         } 
         catch (IOException e) {  
             e.printStackTrace();  
             System.out.println("运行了下载器");  
         }  
     }
}
/**  
 * @ClassName: MyThread  
 * @Description: Thread 实现多图片下载  
 */
public class MyThreadDown extends Thread {  
    private String fileUrl;  
    private String fileName;  
    public MyThreadDown(String fileUrl, String fileName) {  
        this.fileUrl = fileUrl;  
        this.fileName = fileName;  
        System.out.println("成功构造");  
    }  
    @Override  
    public void run(){  
        System.out.println("调用下载器");  
        WebDownLoader loader = new WebDownLoader();  
        loader.downLoader(fileUrl,fileName);  
        System.out.println("下载文件:"+fileName);  
    }  
}
/**  
 * 下载网络图片  
 */  
@Test  
public void downImage(){  
    MyThreadDown m1 = new MyThreadDown("https://scpic.chinaz.net/files/pic/pic9/202112/bpic25011.jpg", "1.jpg");  
    MyThreadDown m2 = new MyThreadDown("https://scpic.chinaz.net/files/pic/pic9/202112/bpic25012.jpg", "2.jpg");  
    MyThreadDown m3 = new MyThreadDown("https://scpic.chinaz.net/files/pic/pic9/202112/bpic25013.jpg", "3.jpg");  
    m1.start();  
    m2.start();  
    m3.start();  
}

火车票抢票问题的模拟

/**  
 * @ClassName: ConcurrencyQuestion  
 * @Description: 并发问题的模拟  
 * 火车票抢票模拟  
 * 多线程是不安全的,多线程处理会导致同一个票被多个人抢到  
 */
public class ConcurrencyQuestion implements Runnable {  
 /** 票数 */  
 private int ticketNums = 10;  
 @Override  
 public void run() {  
     while (true){  
         if (ticketNums == 0) {  
             break;  
         }  
         System.out.println(Thread.currentThread().getName()+"拿到了票"+ticketNums--);  
     }  
 }  
 public static void main(String[] args) {  
     ConcurrencyQuestion concurrencyQuestion = new ConcurrencyQuestion();  
     new Thread(concurrencyQuestion,"sun").start();  
     new Thread(concurrencyQuestion,"sun1").start();  
     new Thread(concurrencyQuestion,"sun2").start();  
 }  
}

龟兔赛跑

/**  
 * @ClassName: Race  
 * @Description: 龟兔赛跑模拟  
 */
public class Race implements Runnable {  
 /**胜利者*/  
 private String winner;  
 @Override  
 public void run() {  
     for (int i = 0; i <= 1000; i++) {  
         if (getOver(i)) {  
             break;  
         }  
         //让乌龟稳赢,给兔子下绊子  
         if(Thread.currentThread().getName().equals("兔")&&i==50){  
             try {  
                 Thread.sleep(10);  
                 System.out.println("兔子被石头绊倒了!");  
                 } 
             catch (InterruptedException e) {  
                 e.printStackTrace();  
             }  
         } 
         System.out.println(Thread.currentThread().getName()+"跑了"+i+"步;");  
     }  
 }  
 /**判断比赛是否结束*/  
 public boolean getOver(int i){  
     if(winner!=null){  
         return true;  
     }else {  
         if(i==100){  
             winner = Thread.currentThread().getName();  
             System.out.println(winner+"赢得了比赛!");  
             return true;  
         }  
     } 
     return false;  
 }  
 public static void main(String[] args) {  
     Race race = new Race();  
     new Thread(race,"兔").start();  
     new Thread(race,"龟").start();  
 }  
}
参考视频:https://www.bilibili.com/video/BV1V4411p7EF?spm_id_from=333.1007.top_right_bar_window_custom_collection.content.click&vd_source=a558872bc8c238e86d17d82aaad3f286
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值