• Java多线程


    活动地址:CSDN21天学习挑战赛
    在这里插入图片描述
    🍁博客主页:👉@不会压弯的小飞侠
    欢迎关注:👉点赞👍收藏留言
    系列专栏:👉21天挑战回顾java
    知足上进,不负野心。
    🔥欢迎大佬指正,一起学习!一起加油!

    在这里插入图片描述


    进程与线程

    进程(Process):进程是程序的一次动态执行过程,它经历了从代码加载、执行、到执行完毕的一个完整过程;同时也是并发执行的程序在执行过程中分配和管理资源的基本单位,竞争计算机系统资源的基本单位。

    线程(Thread):线程可以理解为进程中的执行的一段程序片段,是进程的一个执行单元,是进程内可调度实体,是比进程更小的独立运行的基本单位,线程也被称为轻量级进程。

    一、多线程的实现

    1.继承Thread类

    • 方式1:继承Thread类
      • 定义一个类MyThread继承Thread类
      • 在MyThread类中重写run0方法
      • 创建MyThread类的对象
      • 启动线程

    案例分析:

    package com.Thread;
    public class MyThread extends Thread {
        @Override
        public void run() {
            for (int i = 0; i <100 ; i++) {
                System.out.println(i);
            }
        }
    }
    
    
    package com.Thread;
    public class MyThreadTest {
        public static void main(String[] args) {
            MyThread t1=new MyThread();
            MyThread t2=new MyThread();
    //        t1.run();
    //        t2.run();
            //start()导致此线程开始执行,java虚拟机调用此线程的run方法
            t1.start();
            t2.start();
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    1.设置和获取线程名称

    package com.Thread;
    public class MyThread extends Thread {
        public MyThread() {
        }
    
        public MyThread(String name) {
            super(name);
        }
    
        @Override
        public void run() {
            for (int i = 0; i <100 ; i++) {
                //getName()获取线程名称
                System.out.println(getName()+":"+i);
            }
        }
    }
    
    
    
    package com.Thread;
    public class MyThreadTest {
        public static void main(String[] args) {
    //        MyThread t1=new MyThread();
    //        MyThread t2=new MyThread();
           /* //设置线程名称(方式一)
            t1.setName("小马哥");
            t2.setName("小飞侠");*/
    //        t1.run();
    //        t2.run();
            //start()导致此线程开始执行,java虚拟机调用此线程的run方法
            
            //设置线程名称(方式二)
            MyThread t1=new MyThread("小马哥");
            MyThread t2=new MyThread("小飞侠");
    
            t1.start();
            t2.start();
        }
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    2.线程优先级

    • Thread类中设置和获取线程优先级的方法
      • public final int getPriority0):返回此线程的优先级
      • public final void setPriority(int newPriority):更改此线程的优先级

    案例分析:

    package com.priority;
    
    public class MyPriority extends Thread {
        @Override
        public void run() {
            for (int i = 0; i <100 ; i++) {
                System.out.println(getName()+":"+i);
            }
        }
    }
    
    
    package com.priority;
    
    public class MyPriorityTest {
        public static void main(String[] args) {
            MyPriority p1=new MyPriority();
            MyPriority p2=new MyPriority();
            MyPriority p3=new MyPriority();
            p1.setName("线程一");
            p2.setName("线程二");
            p3.setName("线程三");
    
    //        System.out.println(Thread.NORM_PRIORITY);  //5
    //        System.out.println(Thread.MAX_PRIORITY);  //10
    //        System.out.println(Thread.MIN_PRIORITY);  //1
    
            //设置线程优先级
            p1.setPriority(1);
            p2.setPriority(7);
            p3.setPriority(10);  //线程等级越高获取cpu时间片的几率高
    
            p1.start();
            p2.start();
            p3.start();
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    3.线程控制

    方法名说明
    static void sleep(long millis)使当前正在执行的线程停留(暂停执行)指定的毫秒数
    void join()等待这个线程死亡
    void setDaemon(boolean on)将此线程标记为守护线程,当运行的线程都是守护线程时,Java虚拟机将退出

    案例分析:

    package com.control;
    
    public class ThreadSleep extends Thread {
        @Override
        public void run() {
            for (int i = 0; i <100 ; i++) {
                System.out.println(getName()+":"+i);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
    
            }
        }
    }
    
    package com.control;
    
    public class ThreadSleepTest {
        public static void main(String[] args) {
            ThreadSleep s1=new ThreadSleep();
            ThreadSleep s2=new ThreadSleep();
            ThreadSleep s3=new ThreadSleep();
            s1.setName("小马哥");
            s2.setName("小飞侠");
            s3.setName("老六");
            s1.start();
            s2.start();
            s3.start();
    
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    package com.control;
    
    public class ThreadJoin extends Thread{
        @Override
        public void run() {
            for (int i = 0; i <100 ; i++) {
                System.out.println(getName()+":"+i);
            }
        }
    }
    
    package com.control;
    
    public class ThreadJoinTest {
        public static void main(String[] args) {
            ThreadJoin j1=new ThreadJoin();
            ThreadJoin j2=new ThreadJoin();
            ThreadJoin j3=new ThreadJoin();
            j1.setName("老大");
            j2.setName("老二");
            j3.setName("老三");
            j2.start();
            //当j2执行完之后,j1,j3才开始执行
            try {
                j2.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            j1.start();
            j3.start();
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    package com.control;
    
    public class ThreadDaemon extends Thread {
        @Override
        public void run() {
            for (int i = 0; i <100 ; i++) {
                System.out.println(getName()+":"+i);
            }
        }
    }
    
    package com.control;
    
    public class ThreadDaemonTest {
        public static void main(String[] args) {
            ThreadDaemon d1=new ThreadDaemon();
            ThreadDaemon d2=new ThreadDaemon();
    
            d1.setName("张飞");
            d2.setName("关羽");
            //设置主线程,主线程执行完毕之后,守护线程也会很快的结束
            Thread.currentThread().setName("刘备");
            //设置守护线程
            d1.setDaemon(true);
            d2.setDaemon(true);
    
            d1.start();
            d2.start();
    
            for (int i = 0; i <10 ; i++) {
                System.out.println(Thread.currentThread().getName()+":"+i);
            }
    
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    4.线程的生命周期

    在这里插入图片描述

    2.实现Runnable接口的方式实现多线程

    • 方式2:实现Runnable接口
      • 定义一个类MyRunnable实现Runnable接口
      • 在MyRunnable类中重写run()方法
      • 创建MyRunnable类的对象
      • 创建Thread类的对象,把MyRunnable对象作为构造方法的参数
      • 启动线程
    • 多线程的实现方案有两种
      • 继承Thread类
      • 实现Runnable接口
    • 相比继承Thread类,实现Runnable接口的好处
      • 避免了Java单继承的局限性
      • 适合多个相同程序的代码去处理同一个资源的情况,把线程和程序的代码、数据有效分离,较好子的体现了面向对象的设计思想。

    案例分析:

    package com.Runnable;
    
    public class MyRunnable implements Runnable {
        @Override
        public void run() {
            for (int i = 0; i <100 ; i++) {
                System.out.println(Thread.currentThread().getName()+":"+i);
            }
        }
    }
    
    package com.Runnable;
    
    public class MyRunableTest {
        public static void main(String[] args) {
            MyRunnable m=new MyRunnable();
            Thread t1=new Thread(m,"小马哥");
            Thread t2=new Thread(m,"小飞侠");
            t1.start();
            t2.start();
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    二、线程同步

    • 锁多条语句操作共享数据,可以使用同步代码块实现
    • 格式:
    synchronized(任意对象){
         多条语句操作共享数据的代码
    )
    
    • 1
    • 2
    • 3
    • synchronized(任意对象):就相当于给代码加锁了,任意对象就可以看成是一把锁
      同步的好处和弊端
    • 好处:解决了多线程的数据安全问题
    • 弊端:当线程很多时,因为每个线程都会去判断同步上的锁,这是很耗费资源的,无形中会降低程序的运行效率

    案例分析:

    package com.SellTicketTest;
    
    public class SellTicket implements Runnable {
        private int ticket=100;
        private Object obj=new Object();
        @Override
        public void run() {
            while (true) {
                synchronized (obj) {
                    if (ticket > 0) {
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println(Thread.currentThread().getName() + "正在售出第" + ticket + "张票");
                        ticket--;
                    }
                }
            }
        }
    }
    
    
    package com.SellTicketTest;
    
    public class SellTicketTest {
        public static void main(String[] args) {
            SellTicket ticket=new SellTicket();
            Thread t1=new Thread(ticket,"窗口一");
            Thread t2=new Thread(ticket,"窗口二");
            Thread t3=new Thread(ticket,"窗口三");
            t1.start();
            t2.start();
            t3.start();
    
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    三、线程安全的类

    /*
    线程安全的类;
        StringBuffer
        Vector
        HashtabLe
        */
    public c1ass ThreadTest {
        public static void main(string[] args){
             StringBuffer sb = new StringBuffer();
             StringBuilder sb2 = new StringBuilder();
             
             Vector<String> v = new Vector<String>();
             ArrayList<String> array = new ArrayList<string>();
            Hashtable<String,String> ht = new Hashtable<String,string>();
            HashNap<String,string> hm = new HashMap<String,string>();
            List<String> list = Collections.synchronizedList(new ArrayList<String>());
          }
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    四、Lock锁

    • Lock实现提供比使用synchronized方法和语句可以获得更广泛的锁定操作Lock中提供了获得锁和释放锁的方法
      • void lock():获得锁
      • void unlock():释放锁
    • Lock是接口不能直接实例化,这里采用它的实现类ReentrantLock来实例化ReentrantLock的构造方法
      • ReentrantLock():创建一个ReentrantLock的实例

    案例分析:

    package com.lock;
    
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class MyLock implements Runnable {
        private int ticket=100;
        private Lock lock=new ReentrantLock();
        @Override
        public void run() {
            while (true) {
    
                try {
                    lock.lock();
                    if (ticket > 0) {
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println(Thread.currentThread().getName() + "正在售出第" + ticket + "张票");
                        ticket--;
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }finally {
                    lock.unlock();
                }
            }
        }
    }
    
    package com.lock;
    import com.SellTicketTest.SellTicket;
    public class MyLockTest {
        public static void main(String[] args) {
            MyLock ticket=new MyLock();
            Thread t1=new Thread(ticket,"窗口一");
            Thread t2=new Thread(ticket,"窗口二");
            Thread t3=new Thread(ticket,"窗口三");
            t1.start();
            t2.start();
            t3.start();
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    五、生产者消费者模式

    • ava就提供了几个方法供我们使用,这几个方法在Object类中Object类的等待和唤醒方法:
    方法名说明
    void wait()导致当前线程等待,直到另一个线程调用该对象的notify)方法或notifyAll)方法
    void notify()唤醒正在等待对象监视器的单个线程
    void notifyAll()唤醒正在等待对象监视器的所有线程

    案例分析:

     
    class Box{
    	private int milk;
    	private boolean state=false;
    	public synchronized void put(int milk)  {//同步代码块:执行这块代码后,所在线程加锁,不会被抢占使用权。
    		                                     //这时其他线程要执行,需要wait()该线程,notify()其他线程
    		if(state) {  //有奶,不再继续放,put的线程暂停,等待get线程拿出奶
    			try {
    				wait();
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    		}
    		//state=false,没有奶,生产者放入奶,这是第i瓶
    		this.milk=milk;
    		System.out.println("生产者放入第"+this.milk+"瓶奶");
    		state=true;   //有了奶,奶箱不为空,修改奶箱状态
    		notifyAll();  //唤醒其他所有线程(唤醒get线程,取出牛奶)
    	}
    	public synchronized void get()  {
    		if(!state) {  //state=false,没有奶,消费者没法拿出奶,只能等待
    			try {
    				wait();  //消费者的get行为/线程开始等待
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    		}
    		//state=true,有奶,可以拿出,这是第i瓶奶
    		System.out.println("消费者拿出第"+this.milk+"瓶奶");
    		state=false; //拿出以后,box空,修改box状态
    		notifyAll();  //唤醒其他所有线程(唤醒put线程,开始放入)
    	}
    }
     
    class Producer implements Runnable{
    	private Box b;
    	public Producer(Box b) {
    		this.b=b;
    	}
    	@Override
    	public void run() {
    		for(int i=1;i<11;i++) {
    			b.put(i);
    		}
    	}
       
    }
     
    class Customer implements Runnable{
    	private Box b;
    	public Customer(Box b) {
    		this.b=b;
        }
    	@Override
    	public void run() {
    		while(true) {
    			b.get();
    		}
    	}
    }
     
    public class Milk {
    	public static void main(String[] args) {
    		Box b=new Box();    //创建一个奶箱
    		Producer p=new Producer(b);  //都用这个奶箱
    		Customer c=new Customer(b);
    		Thread t1=new Thread(p);    //producer在线程1中
    		Thread t2=new Thread(c);    //customer在线程2中
    		t1.start();
    		t2.start();
    		
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
  • 相关阅读:
    SpringBoot + MyBatis 结合 MVC框架设计 第1关:项目整合 - SpringBoot + MyBatis
    设计模式-原型模式
    PFSK151 3BSE018876R1/3BSC980006R358 有源滤波器和无源滤波器的区别
    金蝶云星空BOS设计器中基础资料字段属性“过滤”设置获取当前界面的基础资料值作为查询条件
    设计模式之构造者(Builder)模式
    希腊字符的发音
    汽车射频之基础
    故障诊断 | GADF+Swin-CNN-GAM 的轴承故障诊断模型附matlab代码
    港联证券:综合施策提振信心 资本市场新一轮深化改革拉开帷幕
    【ModuleBuilder】GP服务实现SDE中两个图层相交选取
  • 原文地址:https://blog.csdn.net/qq_43514330/article/details/126409654