zoukankan      html  css  js  c++  java
  • java——多线程知识点大总结

                                                                                                                                                                                                                                                                                      

    1:理解线程的概念之前,我们有必要先理解一下进程的概念

      程序(Program)是为实现特定目标或解决特定问题而用计算机语言(比如Java语言)编写的命令序列的集合。

      进程指一个程序一次执行过程 

         

    2:线程

        线程又称为轻量级进程,线程是一个程序中实现单一功能的一个指令序列,是一个程序的单个执行流,存在于进程中,是一个进程的一部分。线程不能单独运行,必须在一个进程之内运行。

     

     

     线程的特点

    线程和进程

     

     如何自定义线程类

    线程中的进程

    线程中的常用方法

     

    import java.util.Date;
    
    class TimeThread extends Thread{
        
        @Override
        public void run() {
            for(int i=0;i<=2; i++){
                System.out.println("时间线程:"+new Date());
                try {
                    Thread.sleep(10000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
    class CounterThread extends Thread {
        
        private TimeThread timeThread;
        
        public CounterThread(TimeThread timeThread){
            this.timeThread = timeThread;
        }
        
        @Override
        public void run() {
            for(int i=1;i<=3; i++){
                if(i==2){
                    try {
                        timeThread.join();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("计数器线程:"+i);
            }
        }
    }
    
    public class Program {
        public static void main(String[] args) {
            TimeThread timeThread = new TimeThread();
            timeThread.start();
            new CounterThread(timeThread).start();
        }
    }

    注意:线程对象在调用join方法前必须先调用start方法,否则该线程永远不会进入执行状态。

    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    class TimeThread extends Thread {
    
        public void run() {
            SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss:sss");
            String beforeTime = sdf.format(new Date());
            System.out.println("beforeTime:"+beforeTime);
            try {
                sleep(30000);// 30秒后执行后面代码
            } catch (Exception e) {
                System.out.println("程序捕获了InterruptedException异常!");
            }
            String afterTime = sdf.format(new Date());
            System.out.println("afterTime:"+afterTime);
        }
    }
    
    public class Program {
        public static void main(String[] args) {
            TimeThread timeThread = new TimeThread();
            timeThread.start();
            try{
                Thread.sleep(1000);
            }catch(InterruptedException e){
                e.printStackTrace();
            }
            timeThread.interrupt();
        }
    }

    class CounterThread extends Thread {
    
        Object lockObj;
    
        public CounterThread(Object lockObj) {
            this.lockObj = lockObj;
        }
    
        @Override
        public void run() {
            synchronized (lockObj) {
                System.out.println("计数器线程正在执行......");
                try {
                    lockObj.wait();//当线程执行该行代码后,线程进入阻塞状态;但由于10秒后主线程执行了“counterThread.interrupt();”代码使得该线程阻塞状态结束
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
    public class Test {
    
        public static void main(String[] args) {
            Object lockObj = new Object();
            CounterThread counterThread = new CounterThread(lockObj);
            counterThread.start();
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            counterThread.interrupt();
        }
    }
    import java.util.Date;
    
    class TimeThread extends Thread{
        
        @Override
        public void run() {
            for(int i=0;i<=2; i++){
                System.out.println("时间线程:"+new Date());
                try {
                    Thread.sleep(10000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
    class CounterThread extends Thread {
        
        private TimeThread timeThread;
        
        public CounterThread(TimeThread timeThread){
            this.timeThread = timeThread;
        }
        
        @Override
        public void run() {
            for(int i=1;i<=3; i++){
                if(i==2){
                    try {
                        timeThread.join();
                    } catch (InterruptedException e) {
                        System.out.println("计数器线程提前结束阻塞状态");
                    }
                }
                System.out.println("计数器线程:"+i);
            }
        }
    }
    
    public class Program {
        public static void main(String[] args) {
            TimeThread timeThread = new TimeThread();
            timeThread.start();
            CounterThread counterThread = new CounterThread(timeThread);
            counterThread.start();
            try {
                Thread.sleep(15000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            counterThread.interrupt();//计数器线程执行该行代码后进入阻塞状态,时间线程至少需要消耗30秒才能结束,而15秒后计数器线程调用了interrupt方法致使该计数器线程提前结束阻塞状态。
        }
    }

    守护线程不是将原来线程改为守护线程,而是本来就是守护线程,别忘了setDaemon方法需要在start方法之前调用。

    代码1:
    public class Program {
    
        public static void main(String[] args) {
            CounterThread counterThread = new CounterThread();
            counterThread.setDaemon(true);
            counterThread.start();
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    
    class CounterThread extends Thread {
        
        public void run() {
            int i=1;
            while(true){
                System.out.println("计数器:"+i);
                i++;
            }
        }
    }
    
    代码2:
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    /**
     * 线程中所启动的其他非守护线程线程不会随着该线程的结束而结束
     */
    public class ThreadDead {
    
        public static void main(String[] args) {
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            TimeThread timeThread = new TimeThread();
            timeThread.start();//10秒后“任务管理器”中javaw.exe进程中线程数量会多一条
        }
    }
    
    class TimeThread extends Thread{
    
        @Override
        public void run() {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String currentTime = sdf.format(new Date());
            System.out.println("时间线程,当前时间:"+currentTime);
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            CounterThread counterThread = new CounterThread();
            //counterThread.setDaemon(true);
            counterThread.start();//10秒后“任务管理器”中javaw.exe进程中线程数量会再多一条
            try {
                Thread.sleep(5000);//一个时段后“任务管理器”中javaw.exe进程中线程数量会少一条,但计数器线程依然在工作
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    
    class CounterThread extends Thread {
    
        public void run() {
            int i=1;
            while(true){
                System.out.println("计数器线程:"+i);
                i++;
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

     终止程序——无疾而终

    class CounterThread extends Thread {
    
        private boolean flag = true;
    
        public void stopThread() {
            flag = false;
        }
    
        public void run() {
            int i = 0;
            while (flag) {
                System.out.println("计数器线程:" + i);
                i++;
                try {
                    sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
    public class Program {
        public static void main(String[] args) {
            CounterThread counterThread = new CounterThread();
            counterThread.start();
            try {
                Thread.sleep(15000);// 15秒后线程终止
                counterThread.stopThread();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    终止程序——暴毙死亡

    class CounterThread extends Thread {
    
        @Override
        public void run() {
            int i = 0;
            try {
                while (true) {
                    System.out.println("计数器线程:" + i);
                    i++;
                    Thread.sleep(3000);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    
    public class Program {
        public static void main(String[] args) {
            CounterThread counterThread = new CounterThread();
            counterThread.start();
            try{
                Thread.sleep(1000);
            }catch(InterruptedException e){
                e.printStackTrace();
            }
            counterThread.interrupt();
        }
    }
    
    上面CounterThread类不可这样写:
    class CounterThread extends Thread {
    
        @Override
        public void run() {
            int i=0;
            while(true){
                System.out.println("计数器线程:"+i);
                i++;
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    串行运行

     

    代码1:
    public class Test {
        
        private static Object shareData = new Object();//多线程间共享的数据
    
        public static void main(String[] args) {
            new CounterThread("线程1",shareData).start();
            new CounterThread("线程2",shareData).start();
        }
    }
    
    class CounterThread extends Thread{
    
        private Object shareData;
        
        public CounterThread(String threadName,Object shareData){
            super(threadName);
            this.shareData = shareData;
        }
        
        @Override
        public void run() {
            synchronized (shareData) {
                for (int i = 0; i < 3; i++) {
                    System.out.println(getName() + " : " + i);
                }
            }
        }
    }
    
    代码2:
    public class Test {
    
        public static void main(String[] args) {
            new CounterThread("线程1").start();
            new CounterThread("线程2").start();
        }
    }
    
    class CounterThread extends Thread {
    
        public CounterThread(String threadName) {
            super(threadName);
        }
    
        @Override
        public void run() {
            synchronized (CounterThread.class) {//执行代码3可知道为什么这样做也可以
                for (int i = 0; i < 3; i++) {
                    System.out.println(getName() + " : " + i);
                }
            }
        }
    }
    
    代码3:
    public class Test {
    
        public static void main(String[] args){
            System.out.println(Test.class == Test.class);
        }
    }

    线程之间数据共享——并行运行

    多个线程之间默认并发运行,这种运行方式往往会出现交叉的情况     

         

    线程之间数据共享——串行运行(synchronized)

      

    使原本并发运行的多个线程实现串行运行,即多线程间同步执行,需要通过对象锁机制来实现,synchronized就是一个利用锁实现线程同步的关键字。

     

      多线程同步原理

    为什么通过synchronized就能实现多线程间串行运行呢?

        被synchronized括着的部分就是线程执行临界区,每次仅能有一个线程执行该临界区中的代码:当多个线程中的某个线程先拿到对象锁, 则该线程执行临界区内的代码,其他线程只能在临界区外部等待,当此线程执行完临界区中的代码后,在临界区外部等待的其他线程开始再次竞争以获取对象锁,进而执行临界区中的代码,但只能有一条线程“胜利”。

         临界区中的代码具有互斥性、唯一性和排它性:一个线程只有执行完临界区中的代码另一个线程才能执行

     1 package com.xt.two;
     2 import java.text.*;
     3 import java.util.Date;
     4 
     5 public class SynTest {
     6 
     7     public static void main(String[] args) {
     8         Object lockObj = new Object();
     9         new DisplayThread(lockObj).start();
    10     }
    11 }
    12 
    13 class DisplayThread extends Thread {
    14 
    15     Object lockObj;
    16 
    17     public DisplayThread(Object lockObj) {
    18         this.lockObj = lockObj;
    19     }
    20 
    21     @Override
    22     public void run() {
    23         synchronized (lockObj) {
    24             new TimeThread(lockObj).start();
    25             try {
    26                 sleep(60000);
    27             } catch (InterruptedException e) {
    28                 e.printStackTrace();
    29             }
    30         }
    31     }
    32 }
    33 class TimeThread extends Thread {
    34 
    35     Object lockObj;
    36 
    37     public TimeThread(Object lockObj) {
    38         this.lockObj = lockObj;
    39     }
    40 
    41     @Override
    42     public void run() {
    43         System.out.println("时间线程开始执行......");
    44         synchronized (lockObj) {
    45             DateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
    46             String time = dateFormat.format(new Date());
    47             System.out.println(time);
      
            //为什么这行代码60秒左右才会执行48 //显示器线程和时间线程共享lockObj对象,显示器线程优先进入启动状态,随后执行相应的run方法,当执行同步代码块时lockObj变量所代表的对象锁归显示器线程所有, 49 //进而创建时间线程并使之处于启动状态,此时有一下两种状态: 50 //1、时间线程马上进入执行状态, 51 //马上执行该时间线程run方法,可是由于此时lockObj变量所代表的对象锁被显示器线程持有, 52 //这时时间线程进入阻塞状态,显示器线程再次执行,然后执行sleep方法,显示器线程在继续持有对象锁的前提下 53 //也进入阻塞状态,60秒后显示器线程进入执行状态,随后显示器线程结束,对象锁被释放,进而时间线程开始执行,进而这行代码运行; 54 //2、时间线程并没有马上进入执行状态,显示器线程执行sleep方法,显示器线程在继续持有对象锁的前提下 55 //也进入阻塞状态,此时时间线程进入执行状态,执行该时间线程run方法,执行该方法中第一行输出代码, 56 //可是由于此时lockObj变量所代表的对象锁被显示器线程持有, 57 //所以时间线程并没有执行时间线程run方法内临界区中的代码,这时时间线程也进入阻塞状态,此时显示器和时间两条线程均进去阻塞状态, 58 //等待少于60秒的时间后,显示器线程进入运行状态,随后显示器线程结束,对象锁被释放,进而时间线程开始执行,进而这行代码运行; 59 } 60 } 61 }

    synchronized(this)

    public class Test {
        
        public static void main(String[] args) {
            new CounterThread("线程1").start();
            new CounterThread("线程2").start();
        }
    }
    
    class CounterThread extends Thread{
    
        public CounterThread(String threadName){
            super(threadName);
        }
        
        @Override
        public void run() {
            synchronized (this) {//此时临界区中的代码无法实现串行执行,因为此时对象锁在线程1和线程2之间不共享
                for (int i = 0; i < 3; i++) {
                    System.out.println(getName() + " : " + i);
                }
            }
        }
    }
    public class Test {
    
        public static void main(String[] args) {
            new Thread(new CounterThread(),"线程1").start();
            new Thread(new CounterThread(),"线程2").start();
        }
    }
    
    class CounterThread implements Runnable {
    
        @Override
        public void run() {
            synchronized (this) {// 此时临界区中的代码依然无法实现串行执行,因为每一个独立线程拥有一个独立的锁对象——new CounterThread()。
                           //要明白这两点:
                           //谁调用该run方法?——CounterThread类对象;
                           //谁执行该run方法?——正在执行的线程
                Thread thread = Thread.currentThread();
                for (int i = 0; i < 3; i++) {
                    System.out.println(thread.getName() + ":" + i);
                }
            }
        }
    }
    public class Test {
    
        public static void main(String[] args) {
            Runnable counterThread = new CounterThread();
            new Thread(counterThread,"线程1").start();
            new Thread(counterThread,"线程2").start();
        }
    }
    
    class CounterThread implements Runnable {
    
        @Override
        public void run() {
            synchronized (this) {// 此时临界区中的代码可以实现串行执行,因为此时接口实现类对象充当了对象锁的功能,该对象锁在两个线程之间共享
                Thread thread = Thread.currentThread();
                for (int i = 0; i < 3; i++) {
                    System.out.println(thread.getName() + ":" + i);
                }
            }
        }
    }

    线程死锁

    如果有两个或两个以上的线程都访问了多个资源,而这些线程占用了一些资源的同时又在等待其它线程占用的资源,也就是说多个线程之间都持有了对方所需的资源,而又相互等待对方释放的资源,在这种情况下就会出现死锁。 多个线程互相等待对方释放对象锁,此时就会出现死锁

    public class DeadLockThread {
        // 创建两个线程之间竞争使用的对象
        private static Object lock1 = new Object();
        private static Object lock2 = new Object();
    
        public static void main(String[] args) {
            new ShareThread1().start();
            new ShareThread2().start();
        }
    
        private static class ShareThread1 extends Thread {
            public void run() {
                synchronized (lock1) {
                    try {
                        Thread.sleep(50);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    synchronized (lock2) {
                        System.out.println("ShareThread1");
                    }
                }
            }
        }
    
        private static class ShareThread2 extends Thread {
            public void run() {
                synchronized (lock2) {
                    try {
                        Thread.sleep(50);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    synchronized (lock1) {
                        System.out.println("ShareThread2");
                    }
                }
            }
        }
    }

     线程协作

    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    public class ElectronicWatch {
        
        String currentTime;
        
        public static void main(String[] args) {
            new ElectronicWatch().new DisplayThread().start();
        }
        
        /**
         * 该线程负责显示时间
         */
        class DisplayThread extends Thread{
    
            @Override
            public void run() {
                new TimeThread ().start();
                System.out.println(currentTime);//为什么结果可能为null
            }
        }
        
        /**
         * 该线程负责获取时间
         */
        class TimeThread extends Thread{
    
            @Override
            public void run() {
                try {
                    sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                String pattern = "yyyy-MM-dd HH:mm:ss";
                SimpleDateFormat sdf = new SimpleDateFormat(pattern);
                currentTime = sdf.format(new Date());
            }
        }
    }
    代码2:
    package test;
    
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    public class ElectronicWatch {
        
        String currentTime;
        
        public static void main(String[] args) {
            new ElectronicWatch().new DisplayThread().start();
        }
        
        /**
         * 该线程负责显示时间
         */
        class DisplayThread extends Thread{
    
            @Override
            public void run() {
                TimeThread timeThread = new TimeThread();
                timeThread.start();
                try {
                    sleep(5000);//这种方式不可取:这种方式性能不高
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(currentTime);
            }
        }
        
        /**
         * 该线程负责获取时间
         */
        class TimeThread extends Thread{
    
            @Override
            public void run() {
                try {
                    sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                String pattern = "yyyy-MM-dd HH:mm:ss";
                SimpleDateFormat sdf = new SimpleDateFormat(pattern);
                currentTime = sdf.format(new Date());
            }
        }
    }
    
    代码3:
    package test;
    
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    public class ElectronicWatch {
        
        String currentTime;
        
        public static void main(String[] args) {
            new ElectronicWatch().new DisplayThread().start();
        }
        
        /**
         * 该线程负责显示时间
         */
        class DisplayThread extends Thread{
    
            @Override
            public void run() {
                TimeThread timeThread = new TimeThread();
                timeThread.start();
                try {
                    timeThread.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(currentTime);
            }
        }
        
        /**
         * 该线程负责获取时间
         */
        class TimeThread extends Thread{
    
            @Override
            public void run() {
                try {
                    sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                String pattern = "yyyy-MM-dd HH:mm:ss";
                SimpleDateFormat sdf = new SimpleDateFormat(pattern);
                currentTime = sdf.format(new Date());
            }
        }
    }
    

                   

    代码4:wait和notify方法

                   

    package com.xt.two;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    public class ElectronicWatch {
        
        String currentTime;
        public static Object obj = new Object();
        
        public static void main(String[] args) {
            new ElectronicWatch().new DisplayThread(obj).start();
        }
        
        /**
         * 该线程负责显示时间
         */
        class DisplayThread extends Thread{
    
            Object obj;
            
            public DisplayThread(Object obj) {
                this.obj = obj;
            }
    
            @Override
            public void run() {
                TimeThread tt=new TimeThread (obj);
                tt.start();
                synchronized (obj) {
                    try {
                        obj.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println(currentTime);//为什么结果可能为null
            }
        }
        
        /**
         * 该线程负责获取时间
         */
        class TimeThread extends Thread{
    
            Object obj;
            
            public TimeThread(Object obj) {
                this.obj = obj;
            }
            @Override
            public void run() {
                try {
                    sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                String pattern = "yyyy-MM-dd HH:mm:ss";
                SimpleDateFormat sdf = new SimpleDateFormat(pattern);
                currentTime = sdf.format(new Date());
                synchronized (obj) {
                    obj.notify();
                }
            }
        }
    }

                                                                     

  • 相关阅读:
    【Java】Java网络编程
    (4.47)sql server 中的 values 构造临时表
    阿里时序数据库 telegraf+influxdb+grafana for sqlserver input plugin
    全景互动制作工具
    湖南师范大学的案例
    git观点
    js-cookie对cookie的操作
    hsf的意义在于什么
    Prettier看这一篇就行了
    关于微前端的观点
  • 原文地址:https://www.cnblogs.com/lyxcode/p/9488561.html
Copyright © 2011-2022 走看看