Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >深入理解多线程

深入理解多线程

作者头像
栋先生
发布于 2018-09-29 08:30:58
发布于 2018-09-29 08:30:58
72100
代码可运行
举报
文章被收录于专栏:Java成长之路Java成长之路
运行总次数:0
代码可运行

多线程是java中比较重要的一部分内容,使用多线程有许多的优点: - 提高应用程序的响应。对图形化界面更有意义,可增强用户体验。 - 程序需要实现一些需要等待的任务时,可以提高计算机系统CPU的利用率 - 改善程序结构。将既长又复杂的进程分为多个线程,独立运行,利于理解和修改

本文就多线程来做一个总结,希望可以给予大家一些帮助。

一、多线程的概述和创建

1. 基本概念:程序-进程-线程

  • 程序(program) 是为完成特定任务、用某种语言编写的一组指令的集合。即指一段静态的代码,静态对象。
  • 进程(process) 是程序的一次动态执行过程,它经历了从代码加载、执行到完毕的一个完整过程。动态过程:有它自身的产生、存在和消亡的过程。 如:运行中的QQ,运行中的MP3播放器 程序是静态的,进程是动态的
  • 线程(thread)进程可进一步细化为线程,是一个程序内部的一条执行路径。 是实现并发的机制的一种有效手段。 若一个程序可同一时间执行多个线程,就是支持多线程的

2. 线程的创建和启动

在java中实现多线程可以采用两种方式:继承Thread类、实现Runnable接口

3. Thread类

  1. Thread类是在java.lang包中定义的, 所以不需要导入,一个类只要继承了继承Thread类, 就是一个多线程操作类
  2. 子类中重写Thread类中的run方法, 此方法为线程的主体。
  3. 创建Thread子类对象,即创建了线程对象。
  4. 调用线程对象start方法:启动线程,并调用run方法;并且start方法只能被执行一次。
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class MyThread extends Thread { // 继承Thread类,作为线程的实现类
    private String name; // 表示线程的名称

    public MyThread(String name) {
        this.name = name; // 通过构造方法配置name属性
    }

    public void run() { // 覆写run()方法,作为线程 的操作主体
        for (int i = 0; i < 10; i++) {
            System.out.println(name + "运行,i = " + i);
        }
    }
};

public class ThreadDemo02 {
    public static void main(String args[]) {
        MyThread mt1 = new MyThread("线程A "); // 实例化对象
        MyThread mt2 = new MyThread("线程B "); // 实例化对象
        mt1.start(); // 调用线程主体
        mt2.start(); // 调用线程主体
    }
};

Output: 线程A 运行,i = 0 线程B 运行,i = 0 线程A 运行,i = 1 线程B 运行,i = 1 线程A 运行,i = 2 线程B 运行,i = 2 线程B 运行,i = 3 线程B 运行,i = 4 线程A 运行,i = 3 线程B 运行,i = 5 线程A 运行,i = 4 线程B 运行,i = 6 线程A 运行,i = 5 线程B 运行,i = 7 线程A 运行,i = 6 线程B 运行,i = 8 线程A 运行,i = 7 线程B 运行,i = 9 线程A 运行,i = 8 线程A 运行,i = 9

从例子来看, 确实是并发执行的, 哪个线程先抢到cpu资源, 哪个线程就先执行。

问题:为什么不直接调用run()方法, 而是通过start()方法来调用(或者说start()方法是怎么实现能启动多线程这个功能的)?-批注1

4. Runnable 接口

  1. 定义子类,实现Runnable接口。
  2. 子类中重写Runnable接口中的run方法。
  3. 通过Thread类含参构造器创建线程对象。
  4. 将Runnable接口的子类对象作为实际参数传递Thread类的构造方法中。
  5. 调用Thread类的start方法:开启线程,调用Runnable子类接口的run方法。
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class MyThread implements Runnable { // 实现Runnable接口,作为线程的实现类
    private String name; // 表示线程的名称

    public MyThread(String name) {
        this.name = name; // 通过构造方法配置name属性
    }

    public void run() { // 覆写run()方法,作为线程 的操作主体
        for (int i = 0; i < 10; i++) {
            System.out.println(name + "运行,i = " + i);
        }
    }
};
public class RunnableDemo01 {
    public static void main(String args[]) {
        MyThread mt1 = new MyThread("线程A "); // 实例化对象
        MyThread mt2 = new MyThread("线程B "); // 实例化对象

        Thread t1 = new Thread(mt1); // 实例化Thread类对象
        Thread t2 = new Thread(mt2); // 实例化Thread类对象
        t1.start(); // 启动多线程
        t2.start(); // 启动多线程
    }
};

OUtput: 线程B 运行,i = 0 线程A 运行,i = 0 线程B 运行,i = 1 线程A 运行,i = 1 线程B 运行,i = 2 线程A 运行,i = 2 线程A 运行,i = 3 线程A 运行,i = 4 线程A 运行,i = 5 线程A 运行,i = 6 线程A 运行,i = 7 线程A 运行,i = 8 线程A 运行,i = 9 线程B 运行,i = 3 线程B 运行,i = 4 线程B 运行,i = 5 线程B 运行,i = 6 线程B 运行,i = 7 线程B 运行,i = 8 线程B 运行,i = 9

5. Thread类与Runnable接口的区别

实现Runnable接口比继承Thread类有如下明显优点

  • 适合多个相同程序代码的线程去处理同一个资源
  • 可以避免单继承局限所带来的影响
  • 增强了代码的健壮性, 代码能够被多个线程共享,代码与数据是独立的

综合以上来看,开发中使用Runnable接口是最合适的,在以后的文章中,使用多线程时都将以Runnable接口的实现为操作的重点。

6. 线程的调度

调度策略 - 时间片

- 抢占式:高优先级的线程抢占CPU

java的调度方法 - 同优先级线程组成先进先出队列(先到先服务),使用时间片策略 - 对高优先级,使用优先调度的抢占式策略

二、多线程的常用方法

  • void start(): 启动线程,并执行对象的run()方法
  • run(): 线程在被调度时执行的操作
  • String getName(): 返回线程的名称
  • void setName(String name):设置该线程名称,线程的名称一般在启动线程前设置, 但也允许为已经运行的线程设置名称。允许两个Thread对象有相同的名字, 但为了清晰, 应避免这种情况发生。如果没为线程指定名称, 系统会进行自动命名(从Thread-0、Thread-1依次编号)
  • static currentThread(): 返回当前线程
  • boolean isAlive():判断线程是否活着,活着返回true, 否则返回false
  • void join():可以使用join()方法让一个线程强制运行,线程强制执行期间, 其他线程无法运行,必须等待此线程完成后才可以继承执行。
  • static void sleep(long millis):另当前活动线程在指定的时间段内放弃对cpu控制, 使其他线程有机会被执行, 时间到后重排队
  • void interrupt():当一个线程运行的时候, 另外一个线程可以直接通过interrupt()方法, 中断其运行状态。
  • void setPriority(int newPriority):设置线程的优先级。在java的线程操作中, 所有线程在运行前都会保持在就绪状态,那么此时,哪个线程优先级高,哪个线程就有可能会先被执行。 X_PRIORITY:最高优先级(10) RM_PRIORITY:中等优先级(5),主方法(main)的优先级就是NORM_PRIORITY N_PRIORITY:最低优先级(1)
  • int getPriority():返回线程的优先级
  • static void yield():线程让步,暂停当前正在执行的线程,把执行机会让给优先级相同或这更高的线程;若队列中没有同优先级的线程,忽略此方法
  • void stop():强制线程生命期结束
  • final void setDaemon(boolean on):设置守护进程

三、死锁和同步机制

1. 问题的产生

以卖火车票为例,如果现在要想买火车票的话可以去火车站或者去各个售票点,但是不管有多少个地方可以买火车票,最终一趟列车的火车票数量是固定的,如果把各个售票点理解为各个线程的话,则所有线程应该共同拥有同一份的票数。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class MyThread implements Runnable {
    private int ticket = 5; // 假设一共有5张票

    public void run() {
        for (int i = 0; i < 100; i++) {
            if (ticket > 0) { // 还有票
                try {
                    Thread.sleep(300); // 加入延迟,可以使问题暴露的更加明显(会让线程执行到这里的时候必须切换出去, 不加切换出去的几率小)
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("卖票:ticket = " + ticket--);
            }
        }
    }
};
public class SyncDemo01 {
    public static void main(String args[]) {
        MyThread mt = new MyThread(); // 定义线程对象
        Thread t1 = new Thread(mt); // 定义Thread对象
        Thread t2 = new Thread(mt); // 定义Thread对象
        Thread t3 = new Thread(mt); // 定义Thread对象
        t1.start();
        t2.start();
        t3.start();
    }
};

Output: 卖票:ticket = 5 卖票:ticket = 3 卖票:ticket = 4 卖票:ticket = 2 卖票:ticket = 1 卖票:ticket = 0 卖票:ticket = -1

从执行的结果来看, 卖出的票数成负数,程序代码出现了问题。

程序分析:

如图所示,线程当ticket等于1的时候,假设线程t1先进入if语句,紧接着执行睡眠, 线程被挂起,此时ticket还没有被减1。同理t2、t3线程就会在t1睡眠时候进入if语句,所以在最后,t1、t2、t3都执行了-1,ticket最后就变成了-1。 如果出现重票,原因也是类似的情况。

  • 产生问题的原因:由于一个线程在操作共享数据过程中,未执行完毕的情况下,另外的线程参与进来,导致共享数据存在了安全问题。
  • 如何解决线程的安全问题:必须让一个线程操作共享数据完毕以后,其它线程才有机会参与共享数据的操作。使用线程的同步机制来解决。

2. 同步机制

  • 在代码块上加上“sysnchronized”关键字的话,则此代码块就称为同步代码块
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
sysnchronized(同步监视器){
        //需要被同步的代码(即为操作共享数据的代码)
}

  • 共享数据:多个线程共同操作的同一个数据(变量)
  • 同步监视器:由一个类的对象来充当。哪个线程获取此监视器,谁就执行大括号里被同步的代码。俗称:锁 要求:所有的线程必须共用同一把锁!

注:在实现的方式中,考虑同步的话,可以使用this来充当锁。但是在继承的方式中,慎用this!

  • synchronized还可以放在方法声明中,表示整个方法为同步方法。
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public synchronized void show (String name){ 
        //代码
}

注:同步方法里面的同步监视器是this

3. 卖火车票问题的解决:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//使用同步方法实现
class MyThread1 implements Runnable{
    private int ticket = 5 ;    // 假设一共有5张票  
    public void run(){  
        for(int i=0;i<100;i++){  
            this.sale() ;   // 调用同步方法  
        }  
    }  
    public synchronized void sale(){    // 声明同步方法  
        if(ticket>0){    // 还有票  
            try{  
                Thread.sleep(300) ; // 加入延迟  
            }catch(InterruptedException e){  
                e.printStackTrace() ;  
            }  
            System.out.println("卖票:ticket = " + ticket-- );  
        }  

    }  
};  
//使用同步代码块
class MyThread implements Runnable {
    private int ticket = 5; // 假设一共有5张票

    public void run() {
        for (int i = 0; i < 100; i++) {
            synchronized (this) { // 要对当前对象进行同步
                if (ticket > 0) { // 还有票
                    try {
                        Thread.sleep(300); // 加入延迟
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("卖票:ticket = " + ticket--);
                }
            }
        }

    }
};
public class SyncDemo02 {
    public static void main(String args[]) {
        //分别测试同步代码块和同步方法
        //测试同步代码块
    /*  MyThread mt = new MyThread(); // 定义线程对象
        Thread t1 = new Thread(mt); // 定义Thread对象
        Thread t2 = new Thread(mt); // 定义Thread对象
        Thread t3 = new Thread(mt); // 定义Thread对象
        System.out.println("使用同步代码块:");
        t1.start();
        t2.start();
        t3.start();*/
        //测试同步方法
        MyThread1 mt1 = new MyThread1(); // 定义线程对象
        Thread t11 = new Thread(mt1); // 定义Thread对象
        Thread t21 = new Thread(mt1); // 定义Thread对象
        Thread t31 = new Thread(mt1); // 定义Thread对象
        System.out.println("使用同步方法:");
        t11.start();
        t21.start();
        t31.start();
    }
};

Output: 卖票:ticket = 5 卖票:ticket = 3 卖票:ticket = 4 卖票:ticket = 2 卖票:ticket = 1 卖票:ticket = 0

程序分析:

如图所示,图中的②就是同步监视器,也就是俗称的锁。当没有线程进入时,②是绿色的,表示可以进入。当t1线程进入到run()方法时, ②将变成红色,阻止t2、t3线程的进入。直到t1线程的run()方法执行完毕,释放了②的3(也就是②变成绿色)。这样就保证了共享数据只会被一个线程操作,程序就不会出现重票、错票的情况了。

4. 死锁

产生原因:过多的同步可能导致死锁,不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就形成了线程的死锁。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//死锁的问题:处理线程同步时容易出现。
//不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就形成了线程的死锁
public class DeadLock {
    static StringBuffer sb1 = new StringBuffer();
    static StringBuffer sb2 = new StringBuffer();

    public static void main(String[] args) {
        //线程1
        new Thread() {
            public void run() {
                synchronized (sb1) {
                    try {
                        sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    sb1.append("A");
                    synchronized (sb2) {
                        sb2.append("B");
                        System.out.println(sb1);
                        System.out.println(sb2);
                    }
                }
            }
        }.start();
        //线程2
        new Thread() {
            public void run() {
                synchronized (sb2) {
                    try {
                        sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    sb1.append("C");
                    synchronized (sb1) {
                        sb2.append("D");
                        System.out.println(sb1);
                        System.out.println(sb2);
                    }
                }
            }
        }.start();
    }
}

Output: ……

  • 程序分析: 程序执行过程中,假设线程1先抢到cpu,并且对sb1上锁,执行到sleep(10)的时侯;线程2又抢到cpu,并且对sb2上锁,然后也执行到了sleep(10)。此时线程1没有释放sb1的锁, 线程2无法向下执行;而线程2也没有释放sb2的锁,所以线程1也无法向下执行。就形成了死锁。
  • 解决方法: 专门的算法、原则 尽量减少同步资源的定义

四、线程通信

1. Object类对线程的支持

唤醒和等待:notify、notifyAll、wait Object是所有类的父类,在此类中有以下几个方法是对线程操作有所支持的

No.

方法

类型

描述

1

public final void wait() throws InterruptedException

普通

线程等待

2

public final void wait(long timeout,int nanos) throws InterruptedException

普通

线程等待,并指定等待的最长时间,以毫秒为单位

3

public final void wait(long timeout) throws InterruptedException

普通

线程等待,并制定等待的最长毫秒及纳秒

4

public final void notifyAll()

普通

唤醒第一个等待的线程

5

public final void notify()

普通

唤醒全部等待的线程

  • wait() 与 notify() 和 notifyAll() wait():令当前线程挂起并放弃CPU、同步资源,使别的线程可访问并修改共享资源,而当前线程排队等候再次对资源的访问 notify():唤醒正在排队等待同步资源的线程中优先级最高者结束等待 notifyAll ():唤醒正在排队等待资源的所有线程结束等待.
  • Java.lang.Object提供的这三个方法只有在synchronized方法或synchronized代码块中才能使用, 否则会报java.lang.IllegalMonitorStateException异常

2. 简单应用:使用两个线程打印 1-100. 线程1, 线程2 交替打印

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//使用同步代码块
class PrintNum1 implements Runnable {
    int num = 1;
    Object obj = new Object();

    public void run() {
        while (true) {
            //synchronized()里面可以填写任意可以唯一确定的对象,也可以直接写this
            synchronized (obj) {
                obj.notify();
                if (num <= 100) {
                    try {
                        Thread.currentThread().sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    //输出num的值并且让num加一
                    System.out.println(Thread.currentThread().getName() + ":" + num++);
                } else 
                    break;

                try {
                    obj.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
//使用同步方法
class PrintNum2 implements Runnable {
    private int num = 1;

    @Override
    public void run() {
        while (true) {
            print();
            //1.为什么在这里使用break不能终止线程?
            if(num == 101)
                break;
            System.out.println(num);
        }
    }

    private synchronized void print() {
        notify();
        if(num <= 100){
            try {
                Thread.currentThread().sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + ":" + num++);
        }
        try {
            wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
public class TestCommunication {
    public static void main(String[] args) {
        //测试同步代码块
//      PrintNum1 p = new PrintNum1();
//      Thread t1 = new Thread(p, "甲");
//      Thread t2 = new Thread(p, "乙");
        //测试同步方法
        PrintNum2 p = new PrintNum2();
        Thread t1 = new Thread(p, "甲");
        Thread t2 = new Thread(p, "乙");

        t1.start();
        t2.start();
    }
}

3. 经典例题:生产者/消费者问题

生产者(Productor)将产品交给店员(Clerk),而消费者(Customer)从店员处取走产品,店员一次只能持有固定数量的产品(比如:20),如果生产者试图生产更多的产品,店员会叫生产者停一下,如果店中有空位放产品了再通知生产者继续生产;如果店中没有产品了,店员会告诉消费者等一下,如果店中有产品了再通知消费者来取走产品。 这里可能出现两个问题: 生产者比消费者快时,消费者会漏掉一些数据没有取到。 消费者比生产者快时,消费者会取相同的数据。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/*
    分析:
    1.是否涉及到多线程的问题?是!生产者、消费者
    2.是否涉及到共享数据?有!考虑线程的安全
    3.此共享数据是谁?即为产品的数量
    4.是否涉及到线程的通信呢?存在这生产者与消费者的通信
 */
class Clerk{//店员
    int product;

    public synchronized void addProduct(){//生产产品
        if(product >= 20){
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }else{
            product++;
            System.out.println(Thread.currentThread().getName() + ":生产了第" + product + "个产品");
            notifyAll();
        }
    }
    public synchronized void consumeProduct(){//消费产品
        if(product <= 0){
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }else{
            System.out.println(Thread.currentThread().getName() + ":消费了第" + product + "个产品");
            product--;
            notifyAll();
        }
    }
}

class Producer implements Runnable{//生产者
    Clerk clerk;

    public Producer(Clerk clerk){
        this.clerk = clerk;
    }
    public void run(){
        System.out.println("生产者开始生产产品");
        while(true){
            try {
                Thread.currentThread().sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            clerk.addProduct();

        }
    }
}
class Consumer implements Runnable{//消费者
    Clerk clerk;
    public Consumer(Clerk clerk){
        this.clerk = clerk;
    }
    public void run(){
        System.out.println("消费者消费产品");
        while(true){
            try {
                Thread.currentThread().sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            clerk.consumeProduct();
        }
    }
}
public class TestProduceConsume {
    public static void main(String[] args) {
        Clerk clerk = new Clerk();
        Producer p1 = new Producer(clerk);
        Consumer c1 = new Consumer(clerk);
        Thread t1 = new Thread(p1);//一个生产者的线程
        Thread t3 = new Thread(p1);
        Thread t2 = new Thread(c1);//一个消费者的线程

        t1.setName("生产者1");
        t2.setName("消费者1");
        t3.setName("生产者2");

        t1.start();
        t2.start();
        t3.start();
    }
}

4. 多线程的生命周期

JDK中用Thread.State枚举表示了线程的几种状态 要想实现多线程,必须在主线程中创建新的线程对象。Java语言使用Thread类及其子类的对象来表示线程,在它的一个完整的生命周期中通常要经历如下的五种状态:

  • 新建: 当一个Thread类或其子类的对象被声明并创建时,新生的线程对象处于新建状态
  • 就绪:处于新建状态的线程被start()后,将进入线程队列等待CPU时间片,此时它已具备了运行的条件
  • 运行:当就绪的线程被调度并获得处理器资源时,便进入运行状态, run()方法定义了线程的操作和功能
  • 阻塞:在某种特殊情况下,被人为挂起或执行输入输出操作时,让出 CPU 并临时中止自己的执行,进入阻塞状态
  • 死亡:线程完成了它的全部工作或线程被提前强制性地中止

批注一:Question: Thread中start()和run()的区别 批注二:native关键字

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2015年11月08日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
JAVA多线程详解
分为两种:一类是守护线程,典型是垃圾回收GC;第二类是用户线程,当JVM中都是JVM守护线程,那么当前的JVM将退出。
阮键
2019/08/07
4320
十五、多线程【黑马JavaSE笔记】
假如计算机只有一个CPU,那么CPU在某一个时刻只能执行一条指令,线程只有得到CPU时间片,也就是使用权,才可以执行指令。所以说多线程程序的执行是有随机性,因为谁抢到CPU的使用权是不一定的
啵啵鱼
2022/11/23
2900
十五、多线程【黑马JavaSE笔记】
Java之多线程-------入门
是指从软件或者硬件上实现多个线程并发执行的技术。 具有多线程能力的计算机因有硬件支持而能够在同一时间执行多个线程,提升性能。
楠羽
2022/11/18
3760
Java之多线程-------入门
Java 线程与多线程
一个进程上可以创建多个线程,线程比进程更快的处理单元,而且所占用的资源也小,多线程的应用也是性能最高的。
Mirror王宇阳
2020/11/12
1.9K0
java线程详解(史上最全)
根据本人多年从业以及学习经验,录制了一套最新的Java精讲视频教程,如果你现在也在学习Java,在入门学习Java的过程当中缺乏系统的学习教程,你可以加QQ群654631948领取下学习资料,面试题,开发工具等,群里有资深java老师做答疑,每天也会有基础部分及架构的直播课,也可以加我的微信renlliang2013做深入沟通,只要是真心想学习Java的人都欢迎。
全栈程序员站长
2022/09/08
2690
java线程详解(史上最全)
多线程详解
假如计算机只有一个CPU,那么CPU在某一时刻只能执行一条指令,线程只有得到CPU时间片,也就是使用权,才可以执行指令。所以说多线程程序的执行是有随机性的。
秋落雨微凉
2022/10/25
4510
多线程
线程类 Java使用 java.lang.Thread 类代表线程,所有的线程对象都必须是Thread类或其子类的实例 每个线程的作用是 完成一定的任务,实际上就是执行一段程序流即一段顺序执行的代码 Java使用线程执行体来代表这段程序流。
JokerDJ
2023/11/27
1950
多线程
JUC 多线程基础
如果一个线程对共享变量的修改,能够被其它线程看到,那么就能说明共享变量在线程之间是可见的。如果一个变量在多个线程的工作内存中都存在副本,那么这个变量就是这几个线程的共享变量。
万能青年
2019/08/30
5300
JUC 多线程基础
第二十四天 多线程-多线程&线程安全【悟空教程】
进程:进程指正在运行的程序。确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于运行过程中的程序,并且具有一定独立功能。
Java帮帮
2018/07/26
6540
第二十四天 多线程-多线程&线程安全【悟空教程】
Java多线程(全知识点)
概述:本文为Java多线程的基础知识点的第一部分,主要包括,通过继承Thread来实现进程,线程调度,线程控制,run(),start(),join(),sleep(),setDaemon()方法的使用,获取线程名字currentThread(),线程同步,非静态锁,静态方法的锁,Lock锁,生产者与消费者问题,卖票问题。
GeekLiHua
2025/01/21
1410
Java多线程(全知识点)
Java 多线程之 Runnable VS Thread 及其资源共享问题
对于 Java 多线程编程中的 implements Runnable 与 extends Thread,部分同学可能会比较疑惑,它们之间究竟有啥区别和联系呢?他们是不是没啥区别随便选呢?实际中究竟该
用户1177713
2018/02/24
9200
Java 多线程之 Runnable VS Thread 及其资源共享问题
第二十五天 多线程-常用方法&线程池【悟空教程】
System.out.println(getName() + " ==== " + i );
Java帮帮
2018/07/26
3900
第二十五天 多线程-常用方法&线程池【悟空教程】
java_线程、同步、线程池
Java使用 java.lang.Thread 类代表线程,所有的线程对象都必须是Thread类或其子类的实例
咕咕星
2020/08/19
8570
java_线程、同步、线程池
Java-多线程(下)
    线程的同步与死锁是多线程里面最需要重点理解的概念。这种操作的核心问题在于:每一个线程对象轮番强占资源
Java架构师必看
2021/11/11
2500
day18-多线程&线程同步&死锁
在操作系统中,安装了多个程序,并发指的是在一段时间内宏观上有多个程序同时运行,这在单 CPU 系统中,每一时刻只能有一道程序执行,即微观上这些程序是分时的交替运行,只不过是给人的感觉是同时运行,那是因为分时交替运行的时间是非常短的。
张哥编程
2024/12/13
900
java基础第十六篇之多线程
1:线程的概念 进程(任务):一个正在运行的程序 进程的调度:CPU来决定什么时候该运行哪个进程 (时间片轮流法) 线程在一个应用程序中,同时,有多个不同的执行路径,是进程中的实际运作单位。 好处是提高程序效率。
海仔
2019/08/05
2900
Android多线程:继承Thread类、实现Runnable接口使用教程(含实例讲解)
前言 在Android开发中,多线程的使用十分常见 今天,我将全面解析多线程中最常见的2种用法:继承Thread类 & 实现Runnable接口 Carson带你学多线程系列 基础汇总 Android多线程:基础知识汇总 基础使用 Android多线程:继承Thread类使用(含实例教程) Android多线程:实现Runnable接口使用(含实例教程) 复合使用 Android多线程:AsyncTask使用教程(含实例讲解) Android多线程:AsyncTask的原理及源码分析 A
Carson.Ho
2022/03/25
8290
Android多线程:继承Thread类、实现Runnable接口使用教程(含实例讲解)
【19】JAVASE-多线程专题【从零开始学JAVA】
Java 是第一大编程语言和开发平台。它有助于企业降低成本、缩短开发周期、推动创新以及改善应用服务。如今全球有数百万开发人员运行着超过 51 亿个 Java 虚拟机,Java 仍是企业和开发人员的首选开发平台。
用户4919348
2024/05/25
1350
【19】JAVASE-多线程专题【从零开始学JAVA】
Java多线程总结(超详细总结)
— JDK 5.0新增 如何理解实现Callable接口的方式创建多线程比实现Runnable接口创建多线程方式强大? 1. call()可以有返回值的。 2. call()可以抛出异常,被外面的操作捕获,获取异常的信息 3. Callable是支持泛型的
小尘要自信
2023/10/10
3140
Java学习笔记之多线程 生产者 消费者
        所有线程轮流使用CPU的使用权,平均分配每个线程占用CPU的时间片
Jetpropelledsnake21
2022/03/07
6050
Java学习笔记之多线程 生产者 消费者
相关推荐
JAVA多线程详解
更多 >
领券
💥开发者 MCP广场重磅上线!
精选全网热门MCP server,让你的AI更好用 🚀
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验