zoukankan      html  css  js  c++  java
  • java学习笔记之初识多线程

    初识多线程

    一.进程的认识:

      1.进程的理解:

      进程可以理解成正在执行的任务,就是正在运行的程序,进程又分为两种,一种是前台进程,就是我们很直观看见的,另一种是后台进程,就是操作系统启动就有的(系统级的进程),每个进程运行之后都会占用一定的cpu和内存资源;

      比如说:我们打开window任务管理器就可以看到有很多的进程,里面有用户开启的,也有操作系统启动的进程

      2.进程的调度:

      也就是那么多的进程,cpu是怎样运行的呢?

      采用时间片轮转法

     

    二.线程认识

      1.线程的理解

        线程是在进程的内部运行的执行体

        (1).一个进程可以创建多个线程

        (2).进程和线程共同来争夺cpu,而且概率是均等的

        (3).线程依赖进程,不能独立存在

        (4).在java中,一个进程至少有一个线程,main方法被称为主线程;

          我们可以在java的main方法中输出一个1/0;

        (5).进程或者线程都有优先级,优先级高的可以得到更多的时间片和cpu的执行权

        (6).抢占式调度:优先级高的进程可以抢占优先级低的cpu执行权

      2.为什么要搞多线程?

       原因:

        (1).让多个程序同时执行

        (2).提高程序的执行效率

    三.线程的创建

      1.方式一:继承Thread类

        小demo:

    1 //定义一个类,继承Thread类
    2 public  class  MyThread  extends  Thread {
    3 
    4     //重写Thread类的run方法    
    5     public void run(){
    6         System.out.print("我是一个子线程");  
    7     }
    8 }

      

    1 public class Demo {
    2     public static void main(String[] args) {
    3         //创建子类对象,然后调用start();方法
    4         MyThread mt=new MyThread();
    5         mt.start();
    6     }
    7 }

      2.方式二:实现Runnable接口

        小demo:

    //实现类的定义
    public class MyRunnableImpl  implements Runnable {
        //定义一个Runnable实现类,然后重写run方法
        @Override
        public void run() {
            //这里写功能代码
        }
    }
     1 public class Demo {
     2     //使用代码
     3     public static void main(String[] args) {
     4         //new 一个Runnable实现类对象
     5         MyRunnableImpl my=new MyRunnableImpl();
     6         //然后将该实现类对象,传入Thread类的构造方法中,并创建Thread类对象
     7         //调用Thread对象start()方法开启线程
     8         new Thread(my).start();
     9     }
    10 }

      3.关于线程的一些方法使用

      

     1 public class Demo {
     2     public static void main(String[] args) {
     3         /*
     4          * 设置线程的名字:方法一
     5          * 1.通过Thread 类的setName(String  name)方法
     6          */
     7         MyThread mThread=new MyThread();
            mThread.setName("线程名字");
    8 mThread.start(); 9 /* 10 * 设置线程名字:方法二 11 * 2.通过Thread的构造方法 12 * Thread(Runnable r,String name); 13 */ 14 //创建Runnable实现类的对象 15 MyRunnable mr=new MyRunnable(); 16 new Thread(mr,"线程名称").start(); 17 18 } 19 }
     1 public class MyThread extends Thread {
     2     public void run(){
     3         /*
     4          * 获取线程的名字的方法
     5          * 1.通过Thread类的getName()方法
     6          * 
     7          * 2.通过Thread类的静态方法currentThread()获取正在当前线程的对象
     8          *     然后通过getName(),获得线程名称
     9          */
    10         System.out.println("方法一线程的名字是:"+getName());
    11         System.out.println("方法二线程的名字是:"+Thread.currentThread().getName());
    12     }
    13 }

    四.线程的安全

       1.线程安全问题产生的原因:

          当多个线程去访问共享资源时候,就会发生线程安全问题

        先看一个案例:多窗口卖电影票的案例

     1 class  Ticket implements Runnable {
     2     //电影票的数量
     3     private static  int ticket=100;
     4     @Override
     5     public void run() {
     6         while(true){
     7             if(ticket>0){
     8                 //模拟网络延时的场景
     9                 try {
    10                     Thread.sleep(50);
    11                 } catch (InterruptedException e) {
    12                     // TODO Auto-generated catch block
    13                     e.printStackTrace();
    14                 }
    15                 //对票数进行出售(减减操作)
    16                 System.out.println("正在售出第"+ticket--+"张票");
    17             }
    18         }
    19     }
    20 }
    21 public class Demo {
    22     public static void main(String[] args) {
    23         //new 一个实现类对象
    24         Ticket  t=new Ticket();
    25         //创建3个线程对电影票进行售卖
    26         new Thread(t).start();
    27         new Thread(t).start();
    28         new Thread(t).start();
    29         
    30     }
    31 }

      这时候就出现了问题:

        

        出现这个问题的解释:

          当拥还剩一张电影票的时候,拥有cpu执行权的线程运行到while(true)的时候,顺利通过,然后在运行sleep();这时候这个线程进入堵塞状态,电影票还是1,cpu的执行权被另一个线程拿到,也正好运行到while(true),顺利通过,然后在运行sleep();cpu执行权被第三个线程抢去,同样的运行,到最后醒过来的线程会继续执行下面的代码。就产生了负数票的现象

       2.线程安全问题的解决方案:

         (1).同步代码块

        

     1      
     2      //定义一个对象,当做锁对象
     3      static Object obj = new Object();
     4      /*
     5         同步代码块:
     6         参数:锁对象
     7         1:java任何对象都可以作为锁对象
     8         2:所有的线程都必须共享这个锁对象(该对象只有一份)
     9         synchronized(mutex){
    10             //存放需要加锁的代码
    11         }
    12       */
    13     
    14     //实现卖票的代码
    15     @Override
    16     public void run() {
    17         
    18         while(true){
    19             synchronized (obj) {//加锁
    20                 if(tickets > 0 ){
    21                     //模拟一个网络的延时
    22                     try{Thread.sleep(50);}catch(Exception e){}
    23                     System.out.println("正在出售第"+ tickets-- + "张票");
    24                 }
    25             }//解锁
    26         }
    27     }

         (2).同步方法

     1     /*
     2      * 同步方法:对整个方法加锁
     3      * 
     4      * 1:同步方法的锁对象是this,  这里的this必须是同一个
     5      * 2:静态方法的锁对象是:类名.class
     6      */
     7     /*
     8      * 同步代码块和同步方法的区别:
     9      *     1:同步代码块可以对任何一段代码进行加锁
    10      *  2:同步方法是对整个方法都进行加锁
    11      *  
    12      *  
    13      *  3:同步代码块的对象可以自己指定
    14      *  4:同步方法的锁对象必须是this
    15      */
    16     public synchronized void method(){
    17         if (tickets > 0) {
    18             // 模拟一个网络的延时
    19             try {
    20                 Thread.sleep(50);
    21             } catch (Exception e) {
    22             }
    23             System.out.println("正在出售第" + tickets-- + "张票");
    24         }
    25     }
    26 
    27     // 实现卖票的代码
    28     @Override
    29     public void run() {
    30 
    31         while (true) {
    32             method();
    33         }
    34     }

         (3).同步锁

     1 /*
     2      * 同步锁:
     3      *  Lock接口:
     4      *      ReentrantLock实现类:
     5      *         lock();    加锁
     6      *         unlock();解锁
     7      */
     8     
     9     //1:创建锁对象
    10     ReentrantLock rt = new ReentrantLock();
    11     
    12     
    13     // 实现卖票的代码
    14     @Override
    15     public void run() {
    16 
    17         while (true) {
    18             //2:在适当的地方加锁
    19             rt.lock();
    20             
    21             if (tickets > 0) {
    22                 // 模拟一个网络的延时
    23                 try {
    24                     Thread.sleep(50);
    25                 } catch (Exception e) {
    26                 }
    27                 System.out.println("正在出售第" + tickets-- + "张票");
    28             }
    29             //3:在适当的地方解锁
    30             rt.unlock();
    31         }
    32     }

    五.线程的状态

     

  • 相关阅读:
    怎样获取当前文档的域名
    怎样获取当前网页的URL
    怎样获取所有style节点
    怎样获取所有的script节点
    怎样获取所有的embed节点对象
    怎样获取页面中的所有图片节点
    怎样获取页面中的表单元素节点
    怎样获取页面中所有带href属性的标签集合
    怎样获取当前页面内的全屏状态的元素节点
    怎样获取当前页面的焦点聚焦元素节点
  • 原文地址:https://www.cnblogs.com/xuzhaocai/p/8087964.html
Copyright © 2011-2022 走看看