多线程

**程序:**程序是一段指令集和,是静态的。

**进程:**当一个程序正在执行时,对应一个进程。

​ 进程由程序、数据和PCB(Process Control Block)组成,是操作系统 资源分配和调度的独立单位

**线程:**为了进一步改善资源利用率、提高系统运行效率而引入的机制。 在一个进程中,多个并行的线程分别执行不同的任务,能更有效的利 用系统资源,提高程序运行效率。

线程是进程中的一个相对独立的指令序列,它也可被操作系统独立调 度。

多线程就是指一个进程中有多个正在运行中的且可被独立调度的指令 序列

线程和进程都拥有对应的执行控制结构。但线程是从属于某个进程的, 它只能使用所属进程的内存资源

进程内部的多个线程之间共享该进程的地址空间和资源每个线程有独立的线程栈

线程和进程的关系: 一个进程可以包含多个线程,而一个线程只能属于某一个进程,线程不能 脱离进程而独立运行;

每一个进程至少包含一个线程(称为主线程);

java程序的入口main()方法就 是在主线程中被执行的。 在主线程中可以创建并启动其它的线程;

一个进程内的所有线程共享该进程的内存资源。

创建多线程的方式:

  • 继承Thread类:

    创建Thread类的子类,在子类中重写run()方法。

    可使用Thread类的构造器Thread(String name)为新线程指定名称。

    调用start()方法启动新线程。

    java.lang.Thread类封装了“线程”的功能。

    Thread类的实例代表一个线程对象,借助该实例可以启动和管理一个线 程。

    Thread类的构造函数

    public Thread()

    public Thread(String name) //参数name代表线程名

    public Thread(Runnable target) //参数target为可运行的对象

    Thread类中的方法:

    public void start() //启动线程

    public void run() //线程的进入点。通过定义Thread类的子类,并重写 run()方法以提供子线程要执行的功能。

    public final String getName() //线程名

    Thread类中的两个静态方法

    public static void sleep(long millis) //使得当前线程休眠指定的时间

    public static Thread currentThread() //返回当前线程对象

  • 实现Runnable接口创建线程:

    Thread类的构造函数:

    public Thread(Runnable target)

    public Thread(Runnable target, String name)

    Runnable中只有一个run();方法,实现Runnable的对象必须放在Thread中使用

  • 使用Thread和Runnable的区别:

    1. extends Thread 的话,有一个java局限性,java是单继承,如果一个类继承了Thread,就不能继承其他的类了
    2. implements Runnable 的话,首先是通过实现接口实现,一个类可以实现多个接口,即这个类既然可以作为作为可以被线程执行的目标对象之外,还可以给这个类添加其他的类(即实现多个接口)。

extends Thread创建线程:

/**
 * @ClassName MultiThreadingDemo01
 * @Description extends Thread 创建线程
 * @Author renhongchang
 * @Date 2021/7/20 9:13
 * @Version 1.0
 * @Blog https://rhc-rgb.github.io
 */
public class MultiThreadingDemo01 extends Thread{

    //启动线程

    @Override
    public void run() {
        super.run();
        System.out.println("启动MultiThreadingDemo01的线程");
    }
}

//测试类
public class MultiThreadingDemo01Test {
    public static void main(String[] args) {
        //实例化
        MultiThreadingDemo01 myThread01 = new MultiThreadingDemo01();
        MultiThreadingDemo01 myThread02 = new MultiThreadingDemo01();
        //启动线程
        myThread01.start();
        myThread02.start();
    }
}

implements Runnable创建线程:

/**
 * @ClassName MultiThreadRunnable
 * @Description Runnable创建线程
 * @Author renhongchang
 * @Date 2021/7/20 9:34
 * @Version 1.0
 * @Blog https://rhc-rgb.github.io
 */
public class MultiThreadRunnable implements Runnable{

    @Override
    public void run() {
        System.out.println("this is Runnable Thread");
    }
}

//测试类
public class MultiThreadRunnableTest {
    public static void main(String[] args) {
        Thread myThread = new Thread(new MultiThreadRunnable());
        myThread.start();
    }
}

使用匿名内部类创建线程:

public class MyThread02 extends Thread{
    /**
     * 使用匿名内部类创建线程
     *
     * @param args
     */
    public static void main(String[] args) {
        //循环10次,创建10个进程
        for (int i = 0;i < 10;i++){
            //使用匿名内部类创建线程
            new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName());
                }
            },"this name is " + i).start();
        }

    }
}

线程创建计时器:

/**
 * @ClassName MultiThreadTimer
 * @Description 计时器
 * @Author renhongchang
 * @Date 2021/7/20 9:20
 * @Version 1.0
 * @Blog https://rhc-rgb.github.io
 */
public class MultiThreadTimer extends Thread{
    /**
     * sleep()  让线程里边的方法不运行
     */
    @Override
    public void run() {
        super.run();
        int i = 0;
        while(1 == 1){
            System.out.println("计时器:" + i);
            i++;
            try {
                //线程每延迟一秒循环一次
                sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

//测试类
public class MultiThreadTimerTest {
    public static void main(String[] args) {
        //实例化线程
        MultiThreadTimer myThreadTimer = new MultiThreadTimer();
        //启动线程
        myThreadTimer.start();
    }
}

线程中的方法:

currentThread() : 获取当前线程对象;

在Thread类中定义了三个优先级常量:MIN_PRIORITY, MAX_PRIORITY 和NORM_PRIORITY,其值分别为1, 10, 5。

setPriority(int xxx) : 设置线程优先级,级别为1-10,10为优先级最高,优先级高并不是先执行,只是增加抢占到资源的机会。如果没有 为线程分配优先级,默认为NORM_PRIORITY

Java采用抢占式调度方式,即高优先级线程具有剥夺低优先级线程执 行的权力。 如果一个低优先线程正在执行,这时出现一个高优先级线程,那么低 优先级线程就被停止执行,放弃CPU,退回到等待队列中,让高优先 级线程立即执行。 如果多个线程具有相同的优先级,则按"先来先服务"的原则调度。

Thread类中的static yield()方法用来让当前线程主动放弃CPU,将执 行的机会让给了下一个同级别的线程。

public class MultiThreadDemo02 extends Thread{

    public MultiThreadDemo02(String name) {
        super(name);
    }

    @Override
    public void run() {
        super.run();
        System.out.println("执行了线程对象" + Thread.currentThread().getName());
    }
}

//测试类
public class MultiThreadDemo02Test {
    public static void main(String[] args) {
        //创建线程对象
        MultiThreadDemo02 myThread021 = new MultiThreadDemo02("线程1");
        MultiThreadDemo02 myThread022 = new MultiThreadDemo02("线程2");
        MultiThreadDemo02 myThread023 = new MultiThreadDemo02("线程3");
        MultiThreadDemo02 myThread024 = new MultiThreadDemo02("线程4");

        //优先级
        //第一种方法  使用setPriority()方法
        myThread021.setPriority(10);
        myThread024.setPriority(10);
        //让步
        myThread021.yield();
        //第二种方法
        myThread022.setPriority(Thread.MIN_PRIORITY);
        myThread023.setPriority(Thread.currentThread().MIN_PRIORITY);


        //启动线程
        myThread021.start();
        myThread022.start();
        myThread023.start();
        myThread024.start();
    }
}

public class MultiThreadDemo03 extends Thread {
    //重写有参构造方法
    public MultiThreadDemo03(String name) {
        super(name);
    }

    //重写run()方法

    @Override
    public void run() {
        super.run();
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("线程" + Thread.currentThread().getName() + "执行结束");
    }
}

//测试类
public class MultiThreadDemo03Test {
    public static void main(String[] args) {
        //创建线程对象
        MultiThreadDemo03 multiThreadDemo031 = new MultiThreadDemo03("1111");
        MultiThreadDemo03 multiThreadDemo032 = new MultiThreadDemo03("2222");

        //启动线程
        multiThreadDemo031.start();
        multiThreadDemo032.start();

        //join 插入
        //等待线程终止
        /*如果没有插入方法先执行则先执行主线程(main),即先输出“程序结束” ,
        如果有插入方法,则先执行插入的线程,即“程序结束”在插入的线程执行之后输出*/
        try {
            multiThreadDemo031.join();
            multiThreadDemo031.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        //主线程方法输出
        System.out.println("程序结束");

    }
}

终止线程:

interrupt() :终止线程

isInterrupted() : 获取当前线程是否终止

public class MyThread03 extends Thread{
    @Override
    public void run() {
        super.run();
        int i = 0;

        while(true){
            System.out.println("thread:" + i++);
            //如果线程状态是终止,则结束循环
            if (Thread.currentThread().isInterrupted()){
                System.out.println("线程终止!");
                break;
            }
        }
    }
}

//测试类
public class MyThread03Test {
    public static void main(String[] args) throws InterruptedException {
        //创建线程对象
        MyThread03 myThread03 = new MyThread03();
        //启动线程
        myThread03.start();

        //阻塞20毫秒
        Thread.sleep(20);
        //终止线程
        myThread03.interrupt();
    }
}

同步锁

给代码块加锁:(锁定某个对象)

synchronized (){
   ... 
}

给方法加锁:

public synchronized void method(){    ...}
//实体类
public class Bank {    
    String account;  //构造方法    
    double balance;  //余额    //构造方法    
    public Bank(String account,double balance){        
        this.account = account;        
        this.balance = balance;    
    }    
    //账户取款    
    public void drawAccount(String name) throws InterruptedException {        
        //使用同步锁 给当前 Bank对象加锁        
        synchronized(this){            
            this.balance = this.balance - 200;
            //            
            Thread.sleep(100);            
            System.out.println(name + "取款200 账户余额: " + this.balance);        
        }    
    }
}
public class MyThread extends Thread {    
    String name; //取款人    
    public MyThread(String name) {        
        this.name = name;    
    }    
    //账号、余额 赋值    
    static Bank bank = new Bank("1001",2000);    
    //执行线程任务    
    @Override    
    public void run() {        
        super.run();        
        while (1 == 1){            
            if (bank.balance >= 200){                
                try {                    
                    bank.drawAccount(this.name);                   
                    Thread.sleep(100);                
                } catch (InterruptedException e) {                    
                    e.printStackTrace();               
                }            
            }else{               
                System.out.println("余额不足!!!!");               
                break;            
            }        
        }    
    }
}
//测试类
public class Test {    
    public static void main(String[] args) {        
        MyThread mt1 = new MyThread("张三");        
        MyThread mt2 = new MyThread("李四");        
        MyThread mt3 = new MyThread("王五");        
        mt1.start();        
        mt2.start();        
        mt3.start();   
    }
}

死锁:

/** 
* @ClassName MyThread04 
* @Description 死锁 
* @Author renhongchang 
* @Date 2021/7/20 15:46 
* @Version 1.0 
* @Blog https://rhc-rgb.github.io 
*/
public class MyThread04 extends Thread{    
    String name;    
    //创建两个对象    
    static Object obj1 = new Object();    
    static Object obj2 = new Object();    
    //构造方法    
    public MyThread04(String name) {        
        this.name = name;    
    }    
    @Override    
    public void run() {        
        super.run();        
        if("线程1".equals(this.name)){            
            synchronized(obj1){                
                System.out.println(this.name + "锁定了资源obj1");                
                try {                    
                    Thread.sleep(1000);                
                } catch (InterruptedException e) {          
                    e.printStackTrace();            
                }               
                synchronized(obj2){                  
                    System.out.println(this.name + "锁定了资源obj2");               
                }          
            }       
        }       
        if("线程2".equals(this.name)){    
            synchronized(obj2){       
                System.out.println(this.name + "锁定了资源obj2");         
                try {                 
                    Thread.sleep(1000);         
                } catch (InterruptedException e) {     
                    e.printStackTrace();         
                }            
                synchronized(obj1){    
                    System.out.println(this.name + "锁定了资源obj1");   
                }       
            }       
        }   
    }
}
//测试类
public class MyThread04Test {   
    public static void main(String[] args) {  
        MyThread04 mt1 = new MyThread04("线程1");        
        MyThread04 mt2 = new MyThread04("线程2");     
        mt1.start();      
        mt2.start();  
    }
}

线程间通信:

多个线程之间需要协同完成工作,就需要线程之间进行通信。

wait()用于让当前线程失去操作权限,当前线程进入等待序列

notify()用于随机通知一个持有对象的锁的线程获取操作权限

notifyAll()用于通知所有持有对象的锁的线程获取操作权限

wait(long) 和wait(long,int)用于设定下一次获取锁的距离当前释放锁的时间间隔

在使用的时候要求在synchronize语句中使用

wait() : 让当前线程等待,知道另一个线程调用此对象的notify() 或者调用此对象的 notifyAll() 方法,或者指定的时间以过。当前线程必须锁定此对象

notify() : 唤醒正在等待对象的单个线程。换新的线程将以通常的方式争夺此对象资源;

notifyAll() : 唤醒正在等待对象的所有线程。

包子铺生产包子,消费者吃包子的问题:

/** 
* @ClassName Bun02 
* @Description 包子实体类 
* @Author renhongchang 
* @Date 2021/7/21 9:41 
* @Version 1.0 
* @Blog https://rhc-rgb.github.io
*/
public class Bun02 {   
    private String skin; //包子皮   
    private String fill; //包子馅  
    private boolean flag; //包子状态    
    //包子数量    
    private int count = 0;   
    //最多容纳四个包子    private static final int VOLUME = 4;    
    //包子皮   
    private String[] skins = {"白皮","绿皮"};  
    //包子馅   
    private  String[] fills = {"韭菜馅","大葱馅"};    
    //无参构造   
    public Bun02() { 
    }    
    //getter方法    
    public String[] getSkins() {        
        return skins;  
    }   
    public String[] getFills() {  
        return fills;   
    }   
    public static int getVOLUME() {  
        return VOLUME;  
    }    
    //setter & getter方法 
    public int getCount() { 
        return count;   
    }   
    public void setCount(int count) {    
        this.count = count;   
    }   
    public String getSkin() {  
        return skin;  
    }   
    public void setSkin(String skin) { 
        this.skin = skin;   
    }   
    public String getFill() {  
        return fill;   
    }   
    public void setFill(String fill) {
        this.fill = fill; 
    }   
    public boolean isFlag() {  
        return flag;  
    }   
    public void setFlag(boolean flag) { 
        this.flag = flag;   
    }
}
/** 
* @ClassName Producer02 
* @Description 包子铺生产包子 
* @Author renhongchang 
* @Date 2021/7/21 9:41 
* @Version 1.0 
* @Blog https://rhc-rgb.github.io
*/
public class Producer02 extends Thread{   
    //创建一个包子变量  
    private Bun02 bun02;    
    public Producer02(String name,Bun02 bun02) { 
        super(name);       
        this.bun02 = bun02;  
    }   
    //布置线程任务,生产包子  
    @Override   
    public void run() {  
        super.run();      
        while(true){    
            synchronized(bun02){       
                if (!bun02.isFlag()){  
                    if (bun02.getCount() % 2 == 0){                        
                        bun02.setSkin(bun02.getSkins()[0]);                        
                        bun02.setSkin(bun02.getFills()[0]);                       
                        System.out.println(Thread.currentThread().getName() + "生产了" + bun02.getSkins()[0] + bun02.getFills()[0] + "的包子");  
                        System.out.println("生产了" + (bun02.getCount() + 1) + "个包子了");                    }else{
                        bun02.setSkin(bun02.getSkins()[1]);  
                        bun02.setSkin(bun02.getFills()[1]);   
                        System.out.println(Thread.currentThread().getName() + "生产了" + bun02.getSkins()[1] + bun02.getFills()[1] + "的包子");  
                        System.out.println("生产了" + (bun02.getCount() + 1) + "个包子了"); 
                    }                    
                    //生产一个包子,包子数量加一                  
                    bun02.setCount(bun02.getCount() + 1);        
                    //生产一个休息一会                   
                    try {                    
                        Thread.sleep(2000);     
                    } catch (InterruptedException e) {    
                        e.printStackTrace();             
                    }                   
                    //如果生产足够的包子,则唤醒吃货    
                    if (bun02.getCount() >= bun02.getVOLUME()){   
                        //设置包子状态                  
                        bun02.setFlag(true);          
                        System.out.println("包子生产结束!!快来吃吧"); 
                        bun02.notify();                  
                    }            
                }else {        
                    //如果有包子,等待  
                    try {         
                        bun02.wait();    
                    } catch (InterruptedException e) {  
                        e.printStackTrace();  
                    }           
                }          
            }      
        }   
    }
}
/** 
* @ClassName Consumer02
* @Description 吃货吃包子
* @Author renhongchang
* @Date 2021/7/21 10:34 
* @Version 1.0 
* @Blog https://rhc-rgb.github.io 
*/
public class Consumer02 extends Thread{   
    //创建一个包子变量   
    private Bun02 bun02;
    public Consumer02(String name,Bun02 bun02) { 
        super(name);      
        this.bun02 = bun02; 
    }   
    //布置线程任务,吃包子 
    @Override    
    public void run() { 
        super.run();       
        //如果有包子,一直吃包子   
        while(true){     
            synchronized(bun02){    
                if (bun02.isFlag()){   
                    //吃货吃包子    
                    if (bun02.getCount() % 2 == 0){       
                        //每吃一个包子,包子数量减1         
                        bun02.setCount(bun02.getCount() - 1);     
                        System.out.println(Thread.currentThread().getName() + "吃了" + bun02.getSkins()[0] + bun02.getFills()[0] + "的包子");  
                        System.out.println("剩下" + bun02.getCount() + "个包子了");  
                    }else{                        
                        bun02.setCount(bun02.getCount() - 1);
                        System.out.println(Thread.currentThread().getName() + "吃了" + bun02.getSkins()[1] + bun02.getFills()[1] + "的包子");    
                        System.out.println("剩下" + bun02.getCount() + "个包子了");  
                    }                    
                    //休息一会          
                    try {      
                        Thread.sleep(2000);   
                    } catch (InterruptedException e) {    
                        e.printStackTrace();             
                    }                  
                    //如果包子数量没有,唤醒生产者  
                    if (bun02.getCount() == 0){ 
                        //设置包子状态         
                        bun02.setFlag(false);  
                        System.out.println("包子吃完了,在来几个吧");   
                        bun02.notify();            
                    }                }else {       
                    //如果没有包子,等待  
                    try {                       
                        bun02.wait();    
                    } catch (InterruptedException e) {  
                        e.printStackTrace();         
                    }            
                }          
            }     
        }   
    }
}
/** 
* @ClassName Bun02Test 
* @Description 测试类 
* @Author renhongchang
* @Date 2021/7/21 10:42 
* @Version 1.0 
* @Blog https://rhc-rgb.github.io
*/
public class Bun02Test {    
    public static void main(String[] args) {        
        //创建包子对象        
        Bun02 bun = new Bun02();      
        //创建包子铺线程       
        Producer02 producer01 = new Producer02("李阿姨",bun);  
        producer01.start();   
        Producer02 producer02 = new Producer02("王阿姨",bun);    
        producer02.start();        
        //创建吃货线程      
        Consumer02 consumer01 = new Consumer02("张三",bun); 
        consumer01.start();        
        Consumer02 consumer02 = new Consumer02("李四",bun); 
        consumer02.start();   
    }
}

线程池:

对于更复杂的任务来说这种频繁手动式的创建、管理线程显然是不可取的,因为线程对象使用了大量的内存,在大规模应用程序中,创建、分配和释放多线程对象会产生大量内存管理开销。为此,可以考虑使用Java提供的线程池来创建多线程,进一步优化线程管理。

Executor接口实现线程池管理

步骤:

  1. 创建一个实现Runnable接口或者Callable接口的实现类,同时重写run()或者call()方法;
  2. 创建Runnable接口或者Callable接口的实现类对象;
  3. 使用Executors线程执行器类创建线程池;
  4. 使用ExecutorService执行器服务类的submit()方法将Runnable接口或者Callable接口的实现类对象提交到线程池进行管理;
  5. 线程任务执行完成后,可以使用shutdown()方法关闭线程池。
Executors创建线程池的方法
方法声明功能描述
ExecutorService newCachedThreadPool()创建一个可扩展线程池的执行器。这个线程池执行器适用于启动许多短期任务的应用程序
ExecutorService newFixedThreadPool(int nThreads)创建一个固定线程数量线程池的执行器。这种线程池执行器可以很好的控制多线程任务,也不会导致由于响应过多导致的程序崩溃
ExecutorServicenewSingleThreadExecutor()在特殊需求下创建一个只执行一个任务的单个线程
ScheduledExecutorService newScheduledThreadPool(int corePoolSize)创建一个定长线程池,支持定时及周期性任务执行
public class RunnableImp implements Runnable{   
    @Override    public void run() {      
        System.out.println(Thread.currentThread().getName() + "执行一个线程任务");  
    }
}
public class ThreadPool { 
    public static void main(String[] args) {  
        //创建一个固定线程数量线程池的执行器。这种线程池执行器可以很好的控制多线程任务,也不会导致由于响应过多导致的程序崩溃
        ExecutorService executor = Executors.newFixedThreadPool(2);      
        //将Runnable接口的实现类提交到线程池进行管理
        executor.submit(new RunnableImp());
        executor.submit(new RunnableImp());
        //线程池长度是2 所以不能添加第三个新的线程进去
        executor.submit(new RunnableImp());
        //关闭线程池
        executor.shutdown(); 
        //执行线程任务  (线程池已经关闭,因此不能在提交线程任务)
        executor.submit(new RunnableImp()); 
    }
}

CompletableFuture类实现线程池管理

CompletableFuture对象创建的四个静态方法:

方法声明功能描述
static CompletableFuture runAsync(Runnable runnable)以Runnable函数式接口类型为参数,并使用ForkJoinPool.commonPool()作为它的线程池执行异步代码获取CompletableFuture计算结果为空的对象
static CompletableFuture runAsync(Runnable runnable, Executor executor)以Runnable函数式接口类型为参数,并传入指定的线程池执行器executor来获取CompletableFuture计算结果为空的对象
static CompletableFuture supplyAsync(Supplier supplier)以Supplier函数式接口类型为参数,并使用ForkJoinPool.commonPool()作为它的线程池执行异步代码获取CompletableFuture计算结果非空的对象
static CompletableFuture supplyAsync(Supplier supplier, Executor executor)以Supplier函数式接口类型为参数,并传入指定的线程池执行器executor来获取CompletableFuture计算结果非空的对象
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值