zoukankan      html  css  js  c++  java
  • Java 多线程

    1、程序和进程:

      程序:一个固定的运算逻辑和数据的集合,是一个静态的状态,一般存储在硬盘中

      进程:正在运行的程序,是程序的一次运行,是一个动态的状态

    2、进程和线程:

      进程:一个正在运行的程序,有自己独立的资源分配,是一个独立的个体

      线程:一个独立的执行路径。多线程,一个进程中可能有许多子任务,每个线程都可以独立的完成一个子任务,各个任务之间没有依赖关系,可以单独执行。

    3、并行和并发:

      并行:多个程序同时执行,相互独立。

      并发:多个任务同时发起,但不能同时执行,只能来回切换的执行。在同一个时间段内,将每个程序都执行过。

      问题:并发到底是提升了效率还是降低了效率?

        多个任务都在执行,效率提高了,但对于某一单独任务来说是降低了。

        并发技术解决了各个设备之间速率不同的问题(如内存和硬盘的存储速度不同),大大提高了CPU的利用率。

    4、多线程实现方式(3种):

      继承方式:(代码示例)

    1. 写一个类,继承Thread
    2. 重写run()方法
    3. 创建类对象,对象.start()方法执行

      注:若使用对象.run(),则是普通的执行方法,不会开启新线程

      实现方式:(代码示例)

    1. 写一个类,实现Runnable接口
    2. 重写run()方法
    3. 创建类对象(任务对象)
    4. 创建线程对象,将任务传给线程Thread t = new Thread(任务对象名);
    5. t.start()启动线程,会自动执行run()内容

      两种方式的比较:

    1. 代码复杂程度:第一种方式更简单
    2. 实现原理

        继承Thread,调用start()方法,本质上是调用start0()方法,是本地方法,由C语言实现,java中看不到源代码

        实现Runnable接口,是创建了一个任务对象,将对象传给线程,再开启线程

       3.在设计实用性方面:

        java中继承都是单继承,如果继承了Thread,则无法继承其它类

        Java中对接口的实现可以多实现,不影响程序的编写

      匿名内部类实现方式:(代码示例)

        new Thread(){run () { } }.start();

        new Thread(new Runnable(){run () {} });

    5、多线程中的常用方法:(代码示例)

      1.获取线程的名称getName()

        注意:

        1.如果没有给线程命名,则线程名字从Thread-0开始依次增加

        2.可以使用对象的引用调用此方法,也可以在线程类中调用

        Thread.currentThread().getName()

        3.Runnable实现类中没有此方法

      2.使用对象的引用设置线程名字setName():

        构造方法也可设置线程名字:Thread(Runnable 任务名, String 线程名);

        对象名.setName(String name)

      3.获取当前线程对象Thread.currentThread()

      4.线程休眠Thread.sleep(毫秒)

        作用:当代码在某个位置需要休息时,就使用休眠

        无论哪个线程执行到这里都会休眠

        注意:有一个异常,中断异常InterruptedException,在run()中必须处理,不能声明

      5.守护线程:setDaemon(boolean flag)

        每条线程默认都不是守护线程,只有设定flag为true才会成为守护线程

        特点:守护其它非守护线程,如果其它非守护线程全都挂掉则跟随死亡

      6.设置线程的优先级setPriority()

        NORM_PRIORITY   5

        MAX_PRIORITY    10

        MIN_PRIORITY     1

    6、安全问题(同步)(代码示例:火车站购票)

      多线程在操作共享数据的时候可能会产生线程不安全问题

      解决方法:使用同步代码块

      格式:synchronized(锁对象){需要同步的代码}

      原理:在有线程处于同步代码块之中时,其它线程必须在代码块外等待,直到里面的线程运行结束

      同步方法:当一个方法中所有的代码都在同步代码块中时,可以将方法定义为同步方法

      格式:权限修饰符 synchronized 返回值类型 方法名(参数列表){方法体};

      注:非静态方法的锁对象是this,也就是当前对象

        静态方法的锁对象是 类名.class (在方法区的一个对象)

        如果两条线程操作相同的数据,锁对象必须保持一致

        使用什么锁,一般用保护的数据作为锁对象

    7、死锁

      A线程需要甲资源,同时拥有了乙资源,B线程拥有乙资源,同时需要甲资源,两条线程都不肯释放自己的资源,就会形成死锁。

      有了同步代码块的嵌套,就可能发生死锁。某条线程获取了外层的锁对象A,需要内层的锁对象B,等待;另外一条线程获取了外层的锁对象B,需要内层的锁对象A,等待。两条线程就会形成死锁。

    public class Demo01 {
        //第一种方式:继承Thread,重写run方法,创建对象,对象.start()
        public static void main(String[] args) {
            SellTicket st = new SellTicket();
            SellTicket st1 = new SellTicket();
            SellTicket st2 = new SellTicket();
            st.start();
            st1.start();
            st2.start();
            
        }
    
    }
    class SellTicket extends Thread{
        static int count=100;//使用静态属性共享票数
        @Override
        public void run() {
            while(true){
                if(count>0) {
                    System.out.println(this.getName());
                    String name = Thread.currentThread().getName();
                    System.out.println(name+"...卖出了第"+count--+"张票");
                }else {
                    break;
                }
            }
        }
    
    }
    多线程第一种方式
    public class Demo02 {
        //第二种方式:实现Runnable接口,重写run方法,创建类对象(任务对象)
        //创建线程对象并将任务对象传给线程,线程对象.start()启动    
        public static void main(String[] args) {
            MyTicket mt = new MyTicket();
            Thread t1 = new Thread(mt,"窗口1");
            Thread t2 = new Thread(mt,"窗口2");
            Thread t3 = new Thread(mt,"窗口3");
            t1.start();
            t2.start();
            t3.start();
            
        }
    
    }
    class MyTicket implements Runnable{
        int count = 100;
        @Override
        public void run() {
            while(true){
                if(count>0) {
                    
                    String name = Thread.currentThread().getName();
                    System.out.println(name+"...卖出了第"+count--+"张票");
                }else {
                    break;
                }
            }
            
        }
    }
    多线程第二种方式
    public class Demo03 {
        //第三种方式:匿名内部类
        public static void main(String[] args) {
            new Thread(new MyTicketWindow()).start();
            new Thread(new MyTicketWindow()).start();
            new Thread(new MyTicketWindow()).start();
    
        }
    
    }
    class MyTicketWindow implements Runnable{
        static int count = 100;
        static Object obj = new Object();
        @Override
        public void run() {
            while(true){
                synchronized (obj) {
                    if(count>0) {
                        try {
                            Thread.sleep(200);
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                        String name = Thread.currentThread().getName();
                        System.out.println(name+"...卖出了第"+count--+"张票");
                    }else {
                        break;
                    }
                }
                
            }
            
        }
    }
    多线程第三种实现方式
  • 相关阅读:
    [C++]C++指针和引用及区别
    FMX画图实例
    VCL画图实例
    DelphiXE FireMonkey 如何画图
    教程-Delphi 启动流程
    Delphi类引用示例
    手机UC下载视频M3U8转MP4
    ComputeShader中Counter类型的使用
    ComputeShader中Consume与AppendStructuredBuffer的使用
    通过一个小Trick实现shader的像素识别/统计操作
  • 原文地址:https://www.cnblogs.com/xfdhh/p/11254482.html
Copyright © 2011-2022 走看看