• Java学习:多线程


    多线程

    线程是依赖于进程而存在的。
    A:进程 正在运行的应用程序
    B:线程 进程的执行路径,执行单元

    多线程的两种方案:
    继承Thread类:需重写run()方法。
    实现Runable接口

    启动线程用的是 start()方法

    start()和run()的区别
    start():1.开启线程 2.执行run()方法里面的代码
    run():执行的是线程里面执行的代码,并不会开启线程

    为什么要重写run()
    因为每个线程需要执行的代码都是都是不一样的,
    我们需要将每个线程自己独立执行的代码写到run()方法中执行

    线程不可以多次启动

    线程的调度和控制
    线程休眠(Thread.sleep(毫秒值))
    线程名称(setName(),getName();)
    线程的调度及优先级setPriority(10)(注意默认值是5,区间在1-10之间)
    什么叫线程优先级:说白了就是设置你抢占cpu执行权抢占到的概率

    多线程安全问题
    A:是否是多线程环境
    B:是否有共享数据
    C:是否有多条语句操作共享数据

    如何解决多线程安全问题
    线程安全执行效率就低
    A:同步代码块(测试不是同一个锁的情况,测试是同一个锁的情况)
    synchronized(对象) {
    需要被同步的代码。
    }
    需求:1.测试不是同一把锁的时候线程安全吗? 2.如果是同一把锁线程安全吗?
    两个问题:1.对象是什么 ?
    答:任意对象 ,相当于是一把锁,只要线程进去就把锁锁上
    2.需要同步的代码?
    答:被线程执行的代码

    B:锁对象问题
    a:同步代码块(定义一个抽象类,里面专门定义一个锁)
    任意对象

    b:同步方法(仅适用于实现runable接口)
    public synchronized void sellTicket(){同步代码}
    this

    c:静态同步方法
    类的字节码对象
    public static synchronized void sellTicket() {
    需要同步的代码
    }

    代码如下:

     1             //同步代码块
     2             synchronized (new Object()) {//t1,t2,t3三个线程不共享同一把锁每个线程都有自己的议案锁
     3             //synchronized (obj) {//这样3个线程才可以共享同一把锁    
     4             if (ticket>0) {
     5                     //考虑到实际的生活中,我们需要给每一个线程加入一定的延迟,模拟一下这种效果
     6                     try {
     7                         Thread.sleep(100);
     8                         /**
     9                          * 分析:为什么会出现两张100张票
    10                          * t1抢占到cpu的执行权,此时ticket=100,但是此刻休眠了
    11                          * 此时被t2抢占到了cpu的执行权,此时ticket=100,
    12                          * t1,t2分别睡了100毫秒之后,分别醒来了。。
    13                          * t1此时出售第100张票
    14                          * t2此时出售第100张票
    15                          */
    16                         
    17                         /**
    18                          * 分析:为什么会出现0张票和-1张票
    19                          * 假设此时票池中仅剩1张票了,
    20                          * t1进来休眠了
    21                          * t2进来休眠了
    22                          * t3进来休眠了
    23                          */
    24                     } catch (InterruptedException e) {
    25                         // TODO Auto-generated catch block
    26                         e.printStackTrace();
    27                     }
    28                     
    29                     System.out.println(Thread.currentThread().getName()+"正在出售第:"+ticket--+"张票");
    30                     /**
    31                      * t1醒来,出售的是第1张票,此时tickt=0
    32                      * t2醒来,出售第0张票,此时ticket=-1
    33                      * t3醒来,出售第-1张票,此时ticket=-2
    34                      */
    35                     
    36                     /**
    37                      * ticket--这个动作一共包含几步:
    38                      * 1.打印出ticket此刻本身的值
    39                      * 2.ticket自减1
    40                      * 3.将自减之后的ticket的最新的值赋值给变量ticket
    41                      */
    42                 }
    43             }
    44             //当被同步的代码执行完毕之后,t1手里拿着的obj这个锁才会被释放,
    45             //t1,t2,t3重新抢占cpu的执行权,谁抢到了继续拿着obj这个锁,执行同步代码块中的内容
    46         
    同步代码块
     1     MyThread mt = new MyThread();
     2         
     3         //创建三个窗口
     4         Thread t1 = new Thread(mt);
     5         Thread t2 = new Thread(mt);
     6         Thread t3 = new Thread(mt);
     7         
     8         //给每一个窗口设置姓名
     9         t1.setName("窗口一");
    10         t2.setName("窗口二");
    11         t3.setName("窗口三");
    12         
    13         //开启窗口进行售票
    14         t1.start();
    15         t2.start();
    16         t3.start();
    测试方法

    运行部分结果如图;

    同步方法代码:

     1 同步方法:同步方法是将synchronized关键字加到方法上,同步方法的锁是this
     2     private synchronized void sellTicket() {    
     3         if (ticket>0) {
     4                 //考虑到实际的生活中,我们需要给每一个线程加入一定的延迟,模拟一下这种效果
     5                 try {
     6                     Thread.sleep(100);
     7                 } catch (InterruptedException e) {
     8                     // TODO Auto-generated catch block
     9                     e.printStackTrace();
    10                 }
    11                 
    12                 System.out.println(Thread.currentThread().getName()+"正在出售第:"+ticket--+"张票");
    13             
    14         }
    15     }
    同步方法

    静态同步方法:

     1 private static synchronized void sellTicket() {    
     2     if (ticket>0) {
     3             //考虑到实际的生活中,我们需要给每一个线程加入一定的延迟,模拟一下这种效果
     4             try {
     5                 Thread.sleep(100);
     6             } catch (InterruptedException e) {
     7                 // TODO Auto-generated catch block
     8                 e.printStackTrace();
     9             }
    10             
    11             System.out.println(Thread.currentThread().getName()+"正在出售第:"+ticket--+"张票");
    12         
    13     }
    静态同步方法

    匿名内部类的方式使用多线程
    new Thread() {
    public void run() {
    ...
    }
    }.start();

    new Thread(new Runnable(){
    public void run() {
    ...
    }
    }).start();

    联系代码如下:

     1 //方式1:
     2         new Thread(){
     3             //重写的方法
     4             @Override
     5             public void run() {
     6                 for (int i = 0; i <10; i++) {
     7                     System.out.println(i);
     8                 }
     9             }
    10         }.start();
    11         
    12         //方式2
    13         new Thread(new Runnable() {
    14             @Override
    15             public void run() {
    16                 for (int i = 0; i <10; i++) {
    17                     System.out.println(i);
    18                 }
    19             }
    20         }).start();
    匿名内部类

    JDK5的Lock锁,我们之前造的所有的锁都没有手动释放锁
    static Lock lock = new ReentrantLock();
    枷锁:lock.lock();
    释放锁:lock.unlock();
    可以让我们明确的知道在哪里加锁和释放锁。
    依然写一个卖票的demo,用lock枷锁释放锁,
    为了保证我们创建的锁一定会被释放,用一下代码进行改进
    try{....}finally{.....}

     1 //定义100张票
     2     int ticket = 100;
     3     Object obj = new Object();
     4     //创建一个锁
     5     Lock lock = new ReentrantLock();
     6     
     7     @Override
     8     public void run() {
     9         while (true) {
    10             try{
    11                 //加上锁,获取锁
    12                 lock.lock();
    13                 if (ticket>0) {
    14                         //考虑到实际的生活中,我们需要给每一个线程加入一定的延迟,模拟一下这种效果
    15                         try {
    16                             Thread.sleep(100);
    17                         } catch (InterruptedException e) {
    18                             // TODO Auto-generated catch block
    19                             e.printStackTrace();
    20                         }
    21                         
    22                         System.out.println(Thread.currentThread().getName()+"正在出售第:"+ticket--+"张票");
    23                     }
    24             }finally{
    25                 //这里面的代码一定会被执行
    26                 //释放锁
    27                 lock.unlock();
    28             }
    29             }
    30     
    31     }
    lock锁

    死锁问题
    同步嵌套,锁里面套了一个锁,出现同步嵌套

     1 boolean flag;
     2     
     3     //提供一个有参构造
     4     public DieThread(boolean flag){
     5         this.flag = flag;
     6     }
     7     
     8     @Override
     9     public void run() {
    10         if (flag) {
    11             synchronized (MyLock.objA) {
    12                 System.out.println("if"+"objA");
    13                 synchronized (MyLock.objB) {
    14                     System.out.println("if"+"objB");
    15                 }
    16             }
    17             
    18         }else {
    19             synchronized (MyLock.objB) {
    20                 System.out.println("else"+"objB");
    21                 synchronized (MyLock.objA) {
    22                     System.out.println("else"+"objA");
    23                 }
    24             }
    25             
    26         }
    27         
    28     }
    死锁问题

    线程等待和唤醒机制(案例演示:waitThread,NotifyThread,MyLock,Test)
    锁对象调用wait()锁对象调用notify()

    注意:   
    wait和sleep的区别
    线程等待,在等待的同时释放锁,而sleep()方法在执行的过程中是不会释放锁的

     1 //让等待线程处于等待状态
     2             try {
     3                 MyLock.obj.wait();//当线程处于等待状态的时候,线程就不会继续往下执行了
     4                                   //线程在处于等待的时候,会释放掉自己手中的锁
     5                                  //sleep()这个方法,在线程休息的时候会释放锁码?
     6                                 //答:不会
     7             } catch (InterruptedException e) {
     8                 // TODO Auto-generated catch block
     9                 e.printStackTrace();
    10             }
    11         }
    12         System.out.println("我被唤醒了");
    wait
    1 public void run() {
    2         synchronized (MyLock.obj) {
    3             //唤醒等待线程
    4             MyLock.obj.notify();//唤醒正在等待的线程,唤醒的等待线程的锁对象,必须和等待线程的锁对象一致
    5         }
    6     }
    View Code
     1 WaitThread wt = new WaitThread();
     2         wt.start();
     3         
     4         //睡上5秒钟之后唤醒等待线程
     5         try {
     6             Thread.sleep(5000);
     7         } catch (InterruptedException e) {
     8             // TODO Auto-generated catch block
     9             e.printStackTrace();
    10         }
    11         
    12         
    13         //创建唤醒线程对象
    14         NotifyThread nt = new NotifyThread();
    15         nt.start();
    View Code
  • 相关阅读:
    DataTable转Json就是这么简单(Json.Net DLL (Newtonsoft))
    Mysql查询数据库 整理
    Mysq基础l数据库管理、表管理、增删改数据整理
    zTree基础
    ECharts基础
    layui基础总结
    Bootstrap基础
    JQuery进阶
    JQuery基础总结
    Javascript鼠标键盘事件
  • 原文地址:https://www.cnblogs.com/shaofanglazi/p/6875115.html
Copyright © 2020-2023  润新知