您好,欢迎来到华佗小知识。
搜索
您的当前位置:首页JUC——多线程补充

JUC——多线程补充

来源:华佗小知识

前置可看

线程创建的三种方式

Thread、Runnable、Callable

Thread类 

Runable接口

Callable接口

Lamda表达式

静态代理模式(Thread类的原理)

 如下代码中

  • 真实对象和代理对象都实现了同一个接口
  • 代理对象代理真实角色

好处:

        代理对象可以做很多真实对象做不了的事情

        真实对象专注做自己的事即可 

其中多线程Thread类的底部实现原理就是静态代理模式,不过被代理的实际线程对象是由Thread来创建的。

//静态代理模式
public class StaticProxy {
    public static void main(String[] args) {
        you you=new you();

        //普通调用
        WeddingCompany weddingCompany=new WeddingCompany(you);
        weddingCompany.HappyMarry();

        //lambda表达式调用
        new WeddingCompany(you).HappyMarry();

        //多线程
        new Thread(()-> System.out.println("测试")).start();
    }
}

interface Marry{

    void HappyMarry();
}

//真实角色
class you implements Marry{

    @Override
    public void HappyMarry() {
        System.out.println("鼠鼠结婚了");
    }
}

//代理角色,帮助你结婚
class WeddingCompany implements Marry{

    //代理的对象-->真实角色
    private Marry target;

    public WeddingCompany(Marry target) {
        this.target = target;
    }

    @Override
    public void HappyMarry() {
        before();
        this.target.HappyMarry();
        after();
    }


    private void before() {
        System.out.println("结婚之前,布置现场");
    }

    private void after() {
        System.out.println("结婚之后,收尾款");
    }
}

在Java中,`Thread`类底层使用了静态代理模式来实现线程的创建和管理。静态代理模式是一种结构型设计模式,它允许你通过代理对象来控制对真实对象的访问。在`Thread`类中,`Thread`对象作为代理,用于管理真正执行线程任务的工作线程(实际的线程实例)。

具体来说,`Thread`类的静态代理模式的工作方式如下:

  • 1. **`Thread`类充当代理:** `Thread`类是代理类,它负责处理线程的生命周期、状态变化等。它提供了方法来启动、暂停、恢复、停止线程等操作。
  • 2. **实际线程对象:** 在`Thread`类中,真正执行线程任务的是一个实际的线程对象,这个线程对象通常是继承自`java.lang.Thread`的子类。这个实际的线程对象是被代理的真实对象。
  • 3. **调用`start`方法:** 当你调用`Thread`类的`start`方法时,`Thread`对象首先会执行一些必要的准备工作(例如,状态设置等),然后创建一个实际的线程对象,并调用实际线程对象的`run`方法。
  • 4. **执行线程任务:** 实际的线程对象执行线程任务。这个任务通常是在子类中的`run`方法中实现的,这是你自己定义的任务逻辑。
  • 5. **线程状态管理:** `Thread`类会在合适的时机管理线程的状态变化,例如,当线程启动时,`Thread`对象会将线程状态设置为"RUNNABLE",当线程执行完毕时,`Thread`对象会将线程状态设置为"TERMINATED"。

总之,`Thread`类在底层使用静态代理模式,通过代理对象管理实际线程对象的创建、启动、暂停、停止等操作,以实现对线程的管理和控制。这种方式使得线程的管理更加便捷,同时也遵循了代理模式的思想。

线程状态—五大状态

 

停止线程 

//测试stop
//1.建议线程正常停止--->利用次数,不建议死循环
//2.建议使用标志位--->设置一个标志位
//3.不要使用stop或者destory
public class TestStop implements Runnable{
    //1.设置一个标志位
    private boolean flag=true;
    @Override
    public void run() {
        int i=0;
        while (flag){
            System.out.println("run...Thread"+i++);
        }
    }
    //2.设置公开方法停止线程
    public void stop(){
        this.flag=false;
    }

    public static void main(String[] args) throws IOException {
        TestStop testStop=new TestStop();
        new Thread(testStop).start();

        for(int i=0;i<1000;i++)
        {
            System.out.println("main"+i);
            if(i==900){
                //调用stop方法切换标志位,让线程停止
                testStop.stop();
                System.out.println("线程停止了");
            }
        }


        System.in.read();
    }
}

 线程休眠_sleep

 线程礼让_yeild 

//测试礼让线程
public class TestYield {
    public static void main(String[] args) {
        MyYield myYield=new MyYield();
        new Thread(myYield,"a").start();
        new Thread(myYield,"b").start();
    }
}

class MyYield implements Runnable{

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + "线程开始执行");
        Thread.yield();//礼让
        System.out.println(Thread.currentThread().getName() +"线程停止执行");
    }
}

线程强制执行_join

线程状态观测 

//观察测试线程的状态
public class TestState {
    public static void main(String[] args) throws InterruptedException {
        Thread thread=new Thread(()->{
            for(int i=0;i<5;i++){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            System.out.println("//");
        });


        //观察状态
        Thread.State state = thread.getState();
        System.out.println(state);  //new

        //观察启动后
        thread.start();//启动线程
         state = thread.getState();
        System.out.println(state);//run

        while(state!=Thread.State.TERMINATED){//只要线程不终止,就一直输出状态
            Thread.sleep(100);
            state=thread.getState();//更新线程状态
            System.out.println(state);//输出状态
        }
    }
}

 

 线程优先级

 守护(daemon)线程

线程同步

多个线程操作同一个资源。

同步方法及同步块

弊端

同步块

CopyOnWriteArrayList

java的JUC并发包下安全类型的集合

/**
 * 测试JUC安全类型的集合
 */
public class TestJUC {
    public static void main(String[] args) throws InterruptedException {
        CopyOnWriteArrayList<String> list=new CopyOnWriteArrayList<String>();

        for(int i=0;i<10000;i++){
            new Thread(()->{
                list.add(Thread.currentThread().getName());
            }).start();
        }
        Thread.sleep(3000);
        System.out.println(list.size());
    }
}

安全问题得到解决

 

 在其实现源码里面可以看见有两个JUC的关键词,volatile保证唯一,transient保证序列化的.

 死锁

死锁形成的四个条件: 互斥/请求与保持/不可剥夺条件/循环等待条件。 

Lock(锁)

ReentrantLock可重入锁类.

在CopyOnWriteArrayList里面就有这个类

 

/**
 * 测试lock锁
 */
public class TestLock {
    public static void main(String[] args) {
        TestLock2 testLock2=new TestLock2();
        new Thread(testLock2).start();
        new Thread(testLock2).start();
        new Thread(testLock2).start();
    }
}
class TestLock2 implements Runnable{
    int tickNums=10;

    //定义锁
   private final  ReentrantLock lock=new ReentrantLock();


    @Override
    public void run() {
        while(true){
            try{
                //此处加锁
                lock.lock();
                if(tickNums>0){
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    System.out.println(tickNums--);
                }else
                {
                    break;
                }
            }finally {
                //解锁
                lock.unlock();
            }
        }
    }
}

 

Synchronized和Lock的对比 

 线程协作和通信

生产者和消费者模式

 

管程法

 

代码实现网上大把.就是两个关键点,一个是消费数量的临界值,第二个就是wait 和notify的使用.

信号灯法

上面管程法用的是容器,这里用的是标志位,但是也相当于是容量为1的容器.

线程池

 就像是IO的缓冲池,Mybatis的缓存,数据库的连接池,JVM的常量池

 

public class TestPool {
    public static void main(String[] args) {
        //1.创建服务
        //参数为:线程池大小
        ExecutorService service= Executors.newFixedThreadPool(10);

        //执行
        service.execute(new MyThread());
        service.execute(new MyThread());
        service.execute(new MyThread());
        service.execute(new MyThread());

        //2.关闭连接
        service.shutdown();
    }
}

class MyThread implements Runnable{


    @Override
    public void run() {
            System.out.println(Thread.currentThread().getName());
    }
}

因篇幅问题不能全部显示,请点此查看更多更全内容

Copyright © 2019- huatuo0.cn 版权所有 湘ICP备2023017654号-2

违法及侵权请联系:TEL:199 18 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务