首页 > 编程语言 >java多线程

java多线程

时间:2023-05-29 09:11:28浏览次数:32  
标签:java thread Thread -- 线程 new 多线程 public

java多线程

进程、线程与多线程

  • 进程是执行程序的一次执行过程,是一个动态的概念,是系统支援分配的单位

  • 通常一个进程可以包含一个或多个线程。线程是CPU调度和执行的单位

  • 线程就是独立执行的路径,由cpu调度

  • 线程会带来额外的开销,如cpu调度时间,并发控制开销

  • 每个线程在自己的工作内存中交互,内存控制不当会造成数据的不一致

  • main()称之为主线程,为系统的入口,用于执行整个程序

  • 程序运行时,即使没有自己创建线程,后台也会有多个线程如主线程,gc线程

  • 很多线程是模拟出来的,真正的多线程是指有多个cpu,即多核,如服务器。如果是模拟出来的多线程,即只有一个cpu的情况下,在同一个时间点,cpu只能执行一个代码,因为切换的很快,所以有了同时执行的错觉

线程的三种创建方式

  1. Thread class:继承Thread类
  2. Runnable接口:实现Runnable接口
  3. Callable接口:实现Callable接口

通过继承Thread创建线程

​ 注意:Thread类实现了Runnable接口

流程:

1. 自定义线程类继承Thread类
2. 重写其run()方法,编写程序执行体
3. 创建线程对象,调用start()方法启动线程
public class MyThread extends Thread {
    @Override
    public void run() {
        //run方法线程体
        for (int i = 0; i < 5; i++) {
            System.out.println("run方法线程--"+i);
        }
    }

    public static void main(String[] args) {
        //run方法线程
        MyThread myThread = new MyThread();
        //启动线程,另外线程只能启动一次死亡之后不能重新启动
        myThread.start();
        //主线程
        for (int i = 0; i < 5; i++) {
            System.out.println("主线程--"+i);
        }

    }
}

/*out:
主线程--0
run方法线程--0
主线程--1
run方法线程--1
主线程--2
run方法线程--2
主线程--3
run方法线程--3
主线程--4
run方法线程--4

注意:输出结果不唯一,每次执行结果不一样
线程开启不一定立即执行,是由cpu调度执行

实现Runnable接口创建线程

1. 自定义线程类实现Runnable接口
2. 重写其run()方法,编写程序执行体
3. 创建该实现类对象,创建Thread线程对象(或者创建Thread对象),并且向Thread对象丢入Runnable实现类(代理方法)
public class MyThread implements  Runnable {
    @Override
    public void run() {
        //run方法线程体
        for (int i = 0; i < 5; i++) {
            System.out.println("run方法线程--"+i);
        }
    }

    public static void main(String[] args) {
        //run方法线程
        MyThread myThread = new MyThread();
        //静态代理
        new Thread(myThread).start();
        //主线程
        for (int i = 0; i < 5; i++) {
            System.out.println("主线程--"+i);
        }

    }
}

/*
主线程--0
run方法线程--0
主线程--1
run方法线程--1
主线程--2
主线程--3
run方法线程--2
主线程--4
run方法线程--3
run方法线程--4

相比于前一种更推荐本方法:避免单继承局限,灵活方便,方便一个对象被多个线程使用

例如:

public class MyThread implements  Runnable {
    private  int number=10;
    @Override
    public void run() {
       while (true){
           if(number<=0){
               break;
           }
           //线程休眠,防止cpu速度太快瞬间把票抢完
           try {
               Thread.sleep(10);
           } catch (InterruptedException e) {
               e.printStackTrace();
           }
//当前线程名字
           System.out.println(Thread.currentThread().getName()+"--"+number--);

       }
    }

    public static void main(String[] args) {
        //run方法线程
        MyThread myThread = new MyThread();
        //第二个参数为线程名字
        new Thread(myThread,"李").start();
        new Thread(myThread,"马").start();
        new Thread(myThread,"王").start();


    }
}

/*
马--9
王--10
李--10
马--8
李--8
王--8
马--7
王--6
李--6
王--5
马--4
李--3
李--0
马--2
王--1


注意:至于为什么出现两个人得到同一个数字,或者出现0,则是一些经典的线程同步问题

实现Callable接口创建线程

步骤:

  • 实现Callable接口,需要返回值类型
  • 重写call方法,需要抛出异常
  • 创建目标对象
  • 创建执行服务
  • 提交执行
  • 获取结果
  • 关闭服务
//<>中填写返回值类型(下面call方法的返回值)
public class MyThread implements Callable<Boolean> {
    //重写call方法,返回值保持和<>中的一样
    @Override
    public Boolean call() throws Exception {\
        //具体线程操作写在这里
        return false;
    }
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        MyThread myThread1 = new MyThread();
        MyThread myThread2 = new MyThread();
        MyThread myThread3 = new MyThread();
        //创建执行服务:newFixedThreadPool线程池,参数为线程池大小
        ExecutorService ser = Executors.newFixedThreadPool(3);
        //提交执行:<>中类型就是call的返回类型
        Future<Boolean> r1 = ser.submit(myThread1);
        Future<Boolean> r2 = ser.submit(myThread2);
        Future<Boolean> r3 = ser.submit(myThread3);
        //获取结果:call()返回值
        Boolean rs1 = r1.get();
        Boolean rs2 = r2.get();
        Boolean rs3 = r3.get();
        //关闭服务
        ser.shutdownNow();
    }
}

好处:

  • 可以定义返回值

  • 可以抛出异常

静态代理

代理就是两个对象实现同一个接口,一个是代理对象一个是真实对象,通过代理对象执行真实对象方法。具体方法:代理对象和真实对象实现同一个接口,创建代理对象同时向其中传入一个真实对象,在代理对象中操作真实对象,在外部调用操作代理对象就能够操作真实对象。

例如前面通过实现Runnable接口创建线程就运用了静态代理

	//MyThread是Runnable接口的实现类
        MyThread myThread = new MyThread();
        //静态代理
        new Thread(myThread).start();

好处:

  • 代理对象可以在真实对象基础上做很多拓展
  • 真实对象专注于自己,专注于核心方法

Lambda表达式

为什么使用它?

  • 避免匿名内部类过多
  • 让代码看起来更加简洁
  • 去掉无意义代码留下核心逻辑

函数式接口

  • 理解函数式接口是学习Lambda表达式的关机
  • 函数式接口的定义:
    1. 任何接口,如果只包含唯一一个抽象方法,那么它就是函数式接口
    2. 对于函数式接口,我们可以通过lamda表达式来创建该接口的对象

怎么使用?

public interface MyInterface {
    void lambda();
}
class main {
    public static void main(String[] args) {
//        无参且一行
        MyInterface myInterface =() -> System.out.println("hello world");
//        有参数a
//        MyInterface myInterface =a  -> System.out.println("hello world");
//        多行
//        MyInterface myInterface1 = ()->{
//            System.out.println();
//            System.out.println()
//        };
        
//        上述代码完全类似下面的匿名内部类
//        MyInterface myInterface1 = new MyInterface() {
//            @Override
//            public void lambda() {
//                System.out.println("hello world");
//            }
//        };
    }
}

//out:hello world

线程的五大状态

线程方法

停止线程

  • 可以但不推荐使用JDK提供的stop()、destroy()方法,已经废弃
  • 推荐线程自己停下来
  • 建议使用一个标志位进行终止变量,当flag=false终止线程运行
public class MyThread implements  Runnable {
    private boolean flag = true;
    @Override
    public void run() {
        int i = 0;
        while (flag){
            System.out.println("run........Thread"+i++);
        }
    }
    public void stop(){
        this.flag = false;
        System.out.println("线程已经停止");
    }

    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        new Thread(myThread).start();
        for (int i = 0; i < 10; i++) {
            //不加这一句的话循环速度太快以至于线程还没运行
            System.out.println("main---"+i);
            if(i==5){
                //调用自己写的stop方法
                myThread.stop();
            }
        }
    }
}

/*
main---0
run........Thread0
main---1
run........Thread1
main---2
run........Thread2
main---3
run........Thread3
main---4
run........Thread4
main---5
run........Thread5
线程已经停止
main---6
main---7
main---8
main---9

线程休眠

  • sleep()指定当前线程阻塞的毫秒数
  • 运行状态转为阻塞状态
  • sleep存在异常InterruptedException
  • sleep时间到达后进入就绪状态
  • 其可以模拟网络延时,倒计时等
  • 每一个对象都有一个锁,sleep不会释放锁

没啥可说的固定写法:Thread.sleep()

线程礼让

  • 即让当前正在执行的线程暂停,但不阻塞
  • 把线程从运行转为就绪状态
  • 让cpu重新调度,礼让不一定成功,看cpu心情
  • 固定写法:Thread.yield();
public class MyThread implements  Runnable {
    private boolean flag = true;
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"开始执行");
        Thread.yield();
        System.out.println(Thread.currentThread().getName()+"完成执行");

    }

    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        MyThread myThread1 = new MyThread();
        new Thread(myThread,"a").start();
        new Thread(myThread1,"b").start();

    }
}
/*
a开始执行
b开始执行
b完成执行
a完成执行

线程强制执行

  • Join合并线程,待此线程完成后,才去执行其他线程
  • 可以看作插队
public class MyThread implements  Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println("VIP驾到通通闪开!"+i);
        }
    }

    public static void main(String[] args) throws InterruptedException {
        MyThread myThread1 = new MyThread();
        Thread thread1 = new Thread(myThread1, "vip");
        //主线程
        for (int i = 0; i < 10; i++) {
            if(i==5){
                thread1.start();
                thread1.join();
            }
            System.out.println("我是一个主线程"+i);

        }

    }
}

/*
我是一个主线程0
我是一个主线程1
我是一个主线程2
我是一个主线程3
我是一个主线程4
VIP驾到通通闪开!0
VIP驾到通通闪开!1
VIP驾到通通闪开!2
VIP驾到通通闪开!3
VIP驾到通通闪开!4
我是一个主线程5
我是一个主线程6
我是一个主线程7
我是一个主线程8
我是一个主线程9

线程状态观测

    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) {
                    e.printStackTrace();
                }
            }
            System.out.println("////////");
        });
        //观测状态
        Thread.State state = thread.getState();
        System.out.println(state);
//        启动线程
        thread.start();
        state = thread.getState();
        System.out.println(state);
//        只要线程不终止一直输出状态
        while (state != Thread.State.TERMINATED){
            Thread.sleep(1000);
            state = thread.getState();
            System.out.println(state);
        }
    }

/*
NEW
RUNNABLE
RUNNABLE
TIMED_WAITING
TIMED_WAITING
RUNNABLE
TIMED_WAITING
////////
TERMINATED

线程优先级

  • 线程优先级用数字表示:Thread.MIN_PRIORITY=1;

    ​ Thread.MAX_PRIORITY = 10;

    ​ Thread.NORM_PRIORITY = 5;

    上面为最小最大正常优先级,均为常量

  • 可以使用以下方式改变或者获取优先级:
    1. .getPrioriyt
    1. .setPriority(int xxx)

  • 另外,优先级高并不是一定先执行,而是相对来说权重更高,到底先还是后看cpu调度

public class MyThread implements  Runnable {
    @Override
    public void run() {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName());
    }

    public static void main(String[] args) throws InterruptedException {
        //主线程优先级:主线程优先级无法修改
        System.out.println(Thread.currentThread().getName()+"-----"+Thread.currentThread().getPriority());
        MyThread myThread = new MyThread();
        Thread t1 = new Thread(myThread,"t1");
        Thread t2 = new Thread(myThread,"t2");
        Thread t3 = new Thread(myThread,"t3");
        Thread t4 = new Thread(myThread,"t4");
        Thread t5 = new Thread(myThread,"t5");

//        一定要注意:先设置优先级再启动否则没用
        t1.start();
        t2.setPriority(1);
        t2.start();
        //设置为最大优先级
        t3.setPriority(Thread.MAX_PRIORITY);
        t3.start();

    }
}
/*
main-----5
t3
t2
t1

守护线程

  • daemon
  • 线程分为用户线程和守护线程
  • 虚拟机必须确保用户线程执行完毕
  • 虚拟机不用等待守护线程完毕
  • 守护线程如后台记录操作日志、监控内存、垃圾回收等待
  • 守护线程:字面意思守护用户线程,虚拟机无视是否还有守护线程存在,当用户线程结束时虚拟机关闭
Thread thread = new Thread();
//默认是false代表用户线程,设置为true表示守护线程
thread.setDaemon(true);

线程同步

  • 就是多个线程操作同一个资源

  • 线程同步其实就是一个等待机制,多个需要同时访问对象的线程进入对象等待池形成队列

  • 并发:同一个对象被多个线程操作。如买票

  • 队列和锁保障线程安全性

  • 为了保证数据在方法中被访问时的正确性,在访问时加入锁机制synchronized

  • 与此同时当一个线程获得对象的排它锁,独占资源,其他线程必须等待使用后释放锁即可,可能存在以下问题:

线程同步操作多种不安全问题,具体可以看上面实现Runnable接口创建线程的例子

synchronized(锁)

  • 针对上面所说的问题:我们可以用锁来解决,即synchronized关键字,它包括方法和块两大用法

  • 同步方法,synchronized方法控制对“对象”的访问,每个对象对应一把锁。每个synchronized方法都必须获得调用该方法的对象的锁才能执行,否则阻塞,方法一旦执行就会独占该锁,直到该方法返回。缺陷:若将一个大方法申明为synchronized将会影响效率

  • 同步块:synchronized(obj){} obj称之为同步监视器,其可以是任何对象,但是推荐共享资源作为同步监视器。另外同步方法不用同步监视器因为其同步监视器就是this,就是这个对象本身,或者class

  • 同步监视器执行过程:
    1. 第一个线程访问,锁定同步监视器
    2. 第二个线程访问,发现已经被锁定,无法访问
    3. 第一个线程访问完毕,解锁同步监视器
    4. 第二个线程访问,发现同步监视器没有锁,然后锁定并且访问

使用同步方法解决问题:

public class MyThread implements  Runnable {
    private  int number=10;
    private  boolean flag = true;
    @Override
    public  void run() {
        while (flag) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            buy();
        }
    }
    //上锁,run方法也可以锁
    public synchronized void buy() {
        if (number < 1) {
            flag=false;
            return;
        }
            System.out.println(Thread.currentThread().getName() + "--" + number--);
        }

    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        new Thread(myThread,"李").start();
        new Thread(myThread,"马").start();
        new Thread(myThread,"王").start();
    }
}
/*
李--10
王--9
马--8
马--7
李--6
王--5
马--4
李--3
王--2
马--1

锁块:

public class MyThread implements  Runnable {
    private  int number=10;
    private  boolean flag = true;
    @Override
    public  void run() {
        while (flag) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //同步块,()填变化的量必须是引用类型,锁定的就是传入参数
            synchronized (Integer.valueOf(number)){
                if (number < 1) {
                    flag=false;
                }
                else {
                    System.out.println(Thread.currentThread().getName() + "--" + number--);
                }
            }
            }
        }

    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        new Thread(myThread,"李").start();
        new Thread(myThread,"马").start();
        new Thread(myThread,"王").start();
    }
}

/*
马--10
王--9
李--8
李--7
王--6
马--5
马--4
李--3
王--2
马--1

CopyOnWriteArrayList

//线程安全的arraylist
CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
for (int i = 0; i < 1000; i++) {
    new Thread(()->{
        list.add(Thread.currentThread().getName());
    }).start();
}
Thread.sleep(3000);
System.out.println(list.size());
//1000

死锁

多个线程各自占有一些共享资源,同时互相等待对方占有资源,从而导致两个或多个线程都在等待对方释放资源停止执行的情况。

某一个同步块同时拥有两个以上对象的锁,就可能出现死锁

 //当mirror和lipstick都只有一份时
            //获得mirror
            synchronized (mirror){
//                获得了mirror,此时lipstick被另外一个线程占据等待
//                其释放,与此同时占据lipstick的线程也在等待它释放mirror
//                  于是死锁发生了
                synchronized (lipstick){
                    
                }
            }

产生死锁的必要条件

Lock(锁)

  • JDK5.0开始,java提供更加强大的线程同步机制--通过显式定义同步锁对象来实现同步。同步锁使用Lock充当
  • 每次只能有一个线程对Lock对象加锁,线程开始访问共享资源之前应当先获得Lock锁
  • ReentranLock类实现了Lock,它拥有与synchronized相同的并发性和内存语义,在实现线程安全的控制中,比较常用的是ReentrantLock,可以显式加锁、释放锁
public class MyThread implements  Runnable {
    private static Integer number=10;
    private  boolean flag = true;
    //定义lock锁
    private final  ReentrantLock lock = new ReentrantLock();

    @Override
    public  void run() {
        while (flag) {
            try {
                Thread.sleep(100);
                lock.lock();//加锁,上锁区域就是lock到unlock区域
                if (number < 1) {
                    flag=false;
                }
                else {
                    System.out.println(Thread.currentThread().getName() + "--" +number--);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                //解锁
                lock.unlock();
            }

            }
        }

    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        new Thread(myThread,"李").start();
        new Thread(myThread,"马").start();
        new Thread(myThread,"王").start();
    }
}
/*
马--10
王--9
李--8
李--7
王--6
马--5
王--4
李--3
马--2
马--1

线程协作--生产者消费者问题

生产者消费者问题:生产者消费者共享一个资源,并且生产者和消费者之间相互依赖,互为条件,操作系统学过的不想多说具体如下:

下面两个解决办法后面有具体演示

解决方法1:

解决方法二:信号灯法

java提供了几个方法解决线程之间的通信问题:

注意:以下均是Object类的方法,都只能在同步方法或者同步代码块中使用,否则会抛出异常,另外sleep不会释放锁,wait会释放锁

解决方法一:管程法

public class Test {
    public static void main(String[] args) {
        SynContainer container = new SynContainer();
        new Producer(container).start();
        new Consumer().start();

    }
}

//生产者
class  Producer extends  Thread{
    //缓冲区
  static SynContainer container;

    public Producer(SynContainer container) {
        this.container = container;
    }

    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            container.push(new Chicken(i));
            System.out.println("生产了第"+i+"只鸡");

        }
    }
}

//消费者
class Consumer extends  Thread{
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println("消费了第"+  Producer.container.pop().id+"只鸡");
        }
    }
}

//产品
class Chicken{
    int id;

    public Chicken(int id) {
        this.id = id;
    }
}

//缓冲区
class  SynContainer{
    //需要一个容器大小
    Chicken[]  chickens = new Chicken[10];
//    容器计数器
    int count = 0;
    //生产者放入产品
    public synchronized void  push(Chicken chicken){
        //如果容器满了,等待消费者消费
        if(count==chickens.length){
            //通知消费者消费,生成等待
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }else {
            //如果没有满,我们就需要丢入产品
            chickens[count] = chicken;
            count++;
        }
//        通知消费者可以消费了
        this.notifyAll();
    }

    //消费者消费产品
    public synchronized  Chicken pop()  {
        //判断是否有产品
        if(count==0){
//            等待生产者生产
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

//        存在产品开始消费
        count--;
        Chicken chicken = chickens[count];

//        吃完了通知生产者生产
        this.notifyAll();
        return  chicken;
    }
}
/*
生产了第0只鸡
消费了第0只鸡
生产了第1只鸡
生产了第2只鸡
消费了第1只鸡
生产了第3只鸡
消费了第3只鸡
生产了第4只鸡
消费了第4只鸡
消费了第2只鸡

上面实现的存在一定问题,但是要传达的思想就这样

解决方法二:信号灯法

public class Test {
    public static void main(String[] args) {
        TV tv =new TV();
        new Player(tv).start();
        new Watcher(tv).start();
    }
}

//生产者
class  Player extends  Thread{
    TV tv;

    public Player(TV tv) {
        this.tv = tv;
    }

    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            if(i%2==0){
                this.tv.play("x节目播放中");
            }
            else {
                this.tv.play("y节目播放中");
            }
        }
    }
}

//消费者
class Watcher extends  Thread{
    TV tv;

    public Watcher(TV tv) {
        this.tv = tv;
    }

    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            tv.watch();
        }
    }
}

//产品
class TV{
    //演员表演,观众等待 T
    //观众观看,演员表演  F
    String voice;//表演的节目
    boolean flag = true;
    public synchronized void play(String voice){
        if(!flag){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("演员表演了:"+voice);
        this.notifyAll();
        this.voice = voice;
        this.flag = !this.flag;
    }
    public  synchronized  void  watch(){
        if(flag) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
            System.out.println("观看了"+voice);
//            通知演员表演
            this.notifyAll();
            this.flag = !this.flag;
        }
    }

/*
演员表演了:x节目播放中
观看了x节目播放中
演员表演了:y节目播放中
观看了y节目播放中
演员表演了:x节目播放中
观看了x节目播放中
演员表演了:y节目播放中
观看了y节目播放中
演员表演了:x节目播放中
观看了x节目播放中

线程池

  • 经常创建和销毁、使用量大的资源,对性能影响很大

  • 思路:提前创建好多个线程,放入线程池,使用时直接获取,使用完放回池中。可以避免频繁创建销毁、实现重复利用。

  • 好处:

    • 提高响应速度
    • 降低资源消耗
    • 便于线程管理
      • corePoolSize:核心池大小
      • maximumPoolSize:最大线程数
      • keepAliveTime:线程没有任务时最多保持多少时间后终结
  • 相关api:

    • ExecutorService :真正的线程池接口。常见子类ThreadPoolExecutor
      • 相关方法:
  • Executors:工具类,用于创建并返回不同类型的线程池

public class MyThread implements  Runnable {
    private int number=10;
    private  boolean flag = true;
    @Override
    public  void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName());
        }
    }

    public static void main(String[] args) {
        //创建线程池,参数为大小
        ExecutorService service = Executors.newFixedThreadPool(10);
        //执行
        service.execute(new MyThread());
        service.execute(new MyThread());
        service.execute(new MyThread());
        service.execute(new MyThread());
        service.execute(new MyThread());
//        关闭链接
        service.shutdownNow();
    }
}

/*
pool-1-thread-1
pool-1-thread-1
pool-1-thread-1
pool-1-thread-1
pool-1-thread-1
pool-1-thread-1
pool-1-thread-1
pool-1-thread-1
pool-1-thread-1
pool-1-thread-1
pool-1-thread-2
pool-1-thread-2
pool-1-thread-2
pool-1-thread-2
pool-1-thread-2
pool-1-thread-2
pool-1-thread-2
pool-1-thread-2
pool-1-thread-2
pool-1-thread-2
pool-1-thread-5
pool-1-thread-5
pool-1-thread-5
pool-1-thread-5
pool-1-thread-5
pool-1-thread-5
pool-1-thread-5
pool-1-thread-5
pool-1-thread-5
pool-1-thread-5
pool-1-thread-4
pool-1-thread-4
pool-1-thread-4
pool-1-thread-4
pool-1-thread-4
pool-1-thread-4
pool-1-thread-4
pool-1-thread-4
pool-1-thread-4
pool-1-thread-4
pool-1-thread-3
pool-1-thread-3
pool-1-thread-3
pool-1-thread-3
pool-1-thread-3
pool-1-thread-3
pool-1-thread-3
pool-1-thread-3
pool-1-thread-3
pool-1-thread-3

标签:java,thread,Thread,--,线程,new,多线程,public
From: https://www.cnblogs.com/rainaftersummert/p/17439440.html

相关文章

  • 复习JavaDay08
    GUI编程简介Gui的核心技术:SwingAWT1.因为界面不美观2.需要jre环境!为什么我们要学习?1.可以写出自己心中想要的一些小工具2.工作时候,也可能需要维护到swing界面,概率极小!3.了解MVC架构,了解监听!第一个Frame窗口publicstaticvoidmain(String[]args){ //创建一个图......
  • Java 线程
    栈与栈帧JavaVirtualMachineStacks(Java虚拟机栈)每个线程启动后,虚拟机就会为其分配一块栈内存,是线程私有的。每个栈由多个栈帧(Frame)组成,对应着每次方法调用时所占用的内存;每个线程只能有一个活动栈帧,对应着当前正在执行的那个方法。  线程上下文切换(ThreadContext......
  • Java的Object类的方法
    Java的Object类是所有类的根类,它提供了一些通用的方法。下面是一些常用的Object类方法:1.equals(Objectobj):判断当前对象是否与给定对象相等。默认情况下,equals方法比较的是对象的引用,但可以通过在具体类中重写equals方法来改变其比较行为。2.hashCode():返回当前对象的哈希码......
  • 基于JAVA的springboot+vue摄影跟拍预定管理系统,附源码+数据库+论文+PPT
    1、项目介绍困扰管理层的许多问题当中,摄影跟拍预定管理一定是不敢忽视的一块。但是管理好摄影跟拍预定又面临很多麻烦需要解决,例如有几个方面:第一,往往用户人数都比较多,如何保证能够管理到每一用户;第二,如何在工作琐碎,记录繁多的情况下将摄影跟拍预定的当前情况反应给领导......
  • 树的最大深度-java实现
    使用递归的方法最为简洁、高效;通过主次遍历,主要不为空,书的深度就加一,同时比较右侧树的深度,每次返回最大值; 1publicintmaxDepth(TreeNoderoot){2returnroot==null?0:Math.max(maxDepth(root.left)+1,maxDepth(root.right)+1);3}ViewCode ......
  • 深入理解 Java 虚拟机 —— Java 内存模型与线程
    处理器的效率和一致性(与java内存访问可类比)计算机同时去做几件事情,不仅是因为计算机的运算能力强大了,还有一个很重要的原因是计算机的运算速度与它的存储和通信子系统的速度差距太大,大量的时间都花费在磁盘I/O、网络通信或者数据库访问上。如果不希望处理器在大部分时间里都处......
  • Java学习:使用MyBatis Plus的分页插件和QueryWrapper结合自定义mapper xml实现多表关联
     Vo:/***用来返回给前端展示列表的数据实体*/@DatapublicclassCourseVoimplementsSerializable{privatestaticfinallongserialVersionUID=1L;privateStringid;privateStringtitle;privateStringsubjectParentTitle;private......
  • java全局配置
    <settings><settingname="mapUnderscoreToCamelCase"value="true"/><settingname="cacheEnabled"value="true"/></settings><typeAliases><!--<typeA......
  • java快速写出文本到文件,可追加写入
    我这只是个简单的测试,不知道那些日志框架是不是这么个原理呢,有没有大佬指点一下 publicclassTest{publicstaticvoidmain(String[]args)throwsIOException{Stringaa="啊啊啊啊啊啊啊啊啊啊";Filefile=newFile("D://test.txt");......
  • java的方法
    1.重载:a.方法名相同b.参数类型或个数不同c.返回只可以相同也一直不同注:重载不能只有返回值不同publicclassHello{publicstaticvoidmain(Stringargs[]){System.out.println("helloowrld");System.out.println(add(1,......