多线程与并发编程【线程对象锁、死锁及解决方案、线程并发协作、生产者与消费者模式】(四)-全面详解(学习总结---从入门到深化)

本文涉及的产品
文本翻译,文本翻译 100万字符
图片翻译,图片翻译 100张
语种识别,语种识别 100万字符
简介: 多线程与并发编程【线程对象锁、死锁及解决方案、线程并发协作、生产者与消费者模式】(四)-全面详解(学习总结---从入门到深化)

使用Class作为线程对象锁



语法结构:

synchronized(XX.class){
      //同步代码
 }


synchronized public static void accessVal()


/**
* 定义销售员工类
*/
class Sale{
    private String name;
    public Sale(String name){
this.name = name;
   }
    /**
     * 领取奖金
     */
    synchronized  public static void money(){
            try {
              System.out.println(Thread.currentThread().getName() + " 被领导表扬");
                Thread.sleep(500);
              System.out.println(Thread.currentThread().getName() + " 拿钱");
                Thread.sleep(500);
              System.out.println(Thread.currentThread().getName() + " 对公司表示感谢");
                Thread.sleep(500);
              System.out.println(Thread.currentThread().getName() + " 开开心心的拿钱走人");
           } catch (InterruptedExceptione) {
                e.printStackTrace();
           }
       }
}
class Programmer{
    private String name;
    public Programmer(String name){
         this.name = name;
   }
    /**
     * 打开电脑
     */
    synchronized  public  void computer(){
            try {
              System.out.println(this.name + " 接通电源");
                Thread.sleep(500);
              System.out.println(this.name + " 按开机按键");
                Thread.sleep(500);
              System.out.println(this.name + " 系统启动中");
                Thread.sleep(500);
              System.out.println(this.name + " 系统启动成功");
           } catch (InterruptedExceptione) {
                e.printStackTrace();
           }
   }
    /**
     * 编码
     */
    synchronized public void coding(){
            try {
                    System.out.println(this.name + " 双击Idea");
                Thread.sleep(500);
              System.out.println(this.name + " Idea启动完毕");
                Thread.sleep(500);
              System.out.println(this.name + " 开开心心的写代码");
           } catch (InterruptedExceptione) {
                e.printStackTrace();
           }
       }
    /**
     * 去卫生间
     */
    public void wc(){
        synchronized ("suibian") {
            try {
              System.out.println(this.name + " 打开卫生间门");
                Thread.sleep(500);
              System.out.println(this.name + " 开始排泄");
                Thread.sleep(500);
              System.out.println(this.name + " 冲水");
                Thread.sleep(500);System.out.println(this.name + " 离开卫生间");
           } catch (InterruptedExceptione) {
                e.printStackTrace();
           }
       }
   }
    /**
     * 领取奖金
     */
    public void money(){
        synchronized (Programmer.class) {
            try {
              System.out.println(this.name + " 被领导表扬");
                Thread.sleep(500);
              System.out.println(this.name + " 拿钱");
                Thread.sleep(500);
              System.out.println(this.name + " 对公司表示感谢");
                Thread.sleep(500);
              System.out.println(this.name + " 开开心心的拿钱走人");
           } catch (InterruptedExceptione) {
                e.printStackTrace();
   }
       }
   }
}
/**
* 打开电脑的工作线程
*/
class Working1 extends Thread{
    private  Programmer p;
    public Working1(Programmer p){
        this.p = p;
   }
    @Override
    public void run() {
        this.p.computer();
   }
}
/**
* 编写代码的工作线程
*/
class Working2 extends Thread{
    private  Programmer p;
    public Working2(Programmer p){
        this.p = p;
   }
    @Override
    public void run() {
        this.p.coding();
   }
}
/**
* 去卫生间的线程
*/
class WC extends Thread{
    private  Programmer p;
    public WC(Programmer p){
        this.p = p;
   }
    @Override
    public void run() {
        this.p.wc();
   }
}
/**
* 程序员领取奖金
*/
class ProgrammerMoney extends Thread{
    private  Programmer p;
    public ProgrammerMoney(Programmer p){
        this.p = p;
   }
    @Override
    public void run() {
        this.p.money();
   }
}
/**
* 销售部门领取奖金
*/
class SaleMoney extends  Thread{
    private  Sale p;
    public SaleMoneyThread(Sale p){
        this.p = p;
   }
    @Override
    public void run() {
        this.p.money();
   }
}
public class TestSyncThread {
    public static void main(String[] args)
{
       /* Programmer p = new Programmer("张三");
        Programmer p1 = new Programmer("李四");
        new ProgrammerMoney(p).start();
        new ProgrammerMoney(p1).start();*/
        Sale s = new Sale("张晓丽");
        Sale s1 = new Sale("王晓红");
        new SaleMoney(s).start();
        new SaleMoney(s1).start();
   }
}


使用自定义对象作为线程对象锁



语法结构:

synchronized(自定义对象){
      //同步代码
}


/**
* 定义销售员工类
*/
class Sale{
    private String name;
    public Sale(String name){
        this.name = name;
   }
    /**
     * 领取奖金
     */
    synchronized  public static void money(){
            try {
                System.out.println(Thread.currentThread(). getName() + " 被领导表扬");
                Thread.sleep(500);
              System.out.println(Thread.currentThread().getName() + " 拿钱");
                Thread.sleep(500);
              System.out.println(Thread.currentThread().getName() + " 对公司表示感谢");
                Thread.sleep(500);
              System.out.println(Thread.currentThread().getName() + " 开开心心的拿钱走人");
           } catch (InterruptedExceptione) {
                e.printStackTrace();
           }
       }
}
class Programmer{
    private String name;
    public Programmer(String name){
        this.name = name;
   }
    /**
     * 打开电脑
     */
    synchronized  public  void computer(){
            try {
                   System.out.println(this.name + " 接通电源");
                   Thread.sleep(500);
                   System.out.println(this.name + " 按开机按键");
                   Thread.sleep(500);
                   System.out.println(this.name + " 系统启动中");
                Thread.sleep(500);
              System.out.println(this.name + " 系统启动成功");
           } catch (InterruptedException e) {
                e.printStackTrace();
           }
   }
    /**
     * 编码
     */
    synchronized public void coding(){
            try {
              System.out.println(this.name + " 双击Idea");
                Thread.sleep(500);
              System.out.println(this.name + " Idea启动完毕");
                Thread.sleep(500);
              System.out.println(this.name + " 开开心心的写代码");
           } catch (InterruptedException e) {
                e.printStackTrace();
           }
       }
    /**
     * 去卫生间
     */
    public void wc(){
        synchronized ("suibian") {
            try {
               System.out.println(this.name + " 打开卫生间门");
                Thread.sleep(500);
               System.out.println(this.name + " 开始排泄");
                Thread.sleep(500);
               System.out.println(this.name + " 冲水");
                Thread.sleep(500);
               System.out.println(this.name + " 离开卫生间");
           } catch (InterruptedException e) {
                e.printStackTrace();
           }
       }
 }
    /**
     * 领取奖金
     */
    public void money(){
        synchronized (Programmer.class) {
            try {
                 System.out.println(this.name + " 被领导表扬");
                Thread.sleep(500);
                 System.out.println(this.name + " 拿钱");
                Thread.sleep(500);
                System.out.println(this.name + " 对公司表示感谢");
                Thread.sleep(500);
                System.out.println(this.name + " 开开心心的拿钱走人");
           } catch (InterruptedException e) {
                e.printStackTrace();
           }
       }
   }
}
class Manager{
    private String name;
    public Manager(String name){
        this.name = name;
}
    public String getName(){
        return this.name;
   }
    /**
     * 敬酒
     */
    public void cheers(String mName,String eName){
            try {
                System.out.println(mName + " 来到 " + eName + " 面前");
                Thread.sleep(500);
                System.out.println(eName + " 拿起酒杯");
                Thread.sleep(500);
                System.out.println(mName + " 和 " + eName + " 干杯");
           } catch (InterruptedException e) {
                e.printStackTrace();
           }
   }
}
/**
* 打开电脑的工作线程
*/
class Working1 extends Thread{
    private  Programmer p;
    public Working1(Programmer p){
        this.p = p;
   }
  @Override
    public void run() {
        this.p.computer();
   }
}
/**
* 编写代码的工作线程
*/
class Working2 extends Thread{
    private  Programmer p;
    public Working2(Programmer p){
        this.p = p;
   }
    @Override
    public void run() {
        this.p.coding();
   }
}
/**
* 去卫生间的线程
*/
class WC extends Thread{
    private  Programmer p;
    public WC(Programmer p){
        this.p = p;
   }
    @Override
    public void run() {
        this.p.wc();
   }
}
/**
* 程序员领取奖金
*/
class ProgrammerMoney extends Thread{
    private  Programmer p;
    public ProgrammerMoney(Programmer p){
        this.p = p;
   }
    @Override
    public void run() {
        this.p.money();
   }
}
/**
* 销售部门领取奖金
*/
class SaleMoneyThread extends  Thread{
    private  Sale p;
    public SaleMoneyThread(Sale p){
        this.p = p;
   }
    @Override
    public void run() {
        this.p.money();
   }
}
/**
* 敬酒线程类
*/
class CheersThread extends Thread{
    private Manager manager;
    private String name;
    public CheersThread(String name,Manager manager){
        this.name = name;
        this.manager = manager;
   }
    @Override
    public void run() {
        synchronized (this.manager) {
this.manager.cheers(this.manager.getName() , name);
       }
   }
}
public class TestSyncThread {
    public static void main(String[] args)
{
        Manager manager = new Manager("张三丰");
        new CheersThread("张三",manager).start();
        new CheersThread("李四",manager).start();
   }
}


死锁及解决方案


死锁的概念


“死锁”指的是: 多个线程各自占有一些共享资源,并且互相等待其他线程占有的资 源才能进行,而导致两个或者多个线程都在等待对方释放资源,都 停止执行的情形。


某一个同步块需要同时拥有“两个以上对象的锁”时,就可能会发 生“死锁”的问题。比如,“化妆线程”需要同时拥有“镜子对象”、 “口红对象”才能运行同步块。那么,实际运行时,“小丫的化妆 线程”拥有了“镜子对象”,“大丫的化妆线程”拥有了“口红对象”, 都在互相等待对方释放资源,才能化妆。这样,两个线程就形 成了互相等待,无法继续运行的“死锁状态”。


死锁案例演示

/**
* 口红类
*/
   class Lipstick{
     }
/**
* 镜子类
*/
   class Mirror{
   }
/**
* 化妆线程类
*/
class Makeup extends Thread{
    private int flag; //flag=0:拿着口红。 flag!=0:拿着镜子
    private String girlName;
    static Lipstick lipstick = new Lipstick();
    static Mirror mirror = new Mirror();
    public Makeup(int flag,String girlName){
        this.flag  = flag;
        this.girlName = girlName;
   }
    @Override
    public void run() {
        this.doMakeup();
   }
    /**
     * 开始化妆
     */
    public void doMakeup(){
        if(flag == 0){
            synchronized (lipstick){
              System.out.println(this.girlName+" 拿着口红");
                try {
                    Thread.sleep(1000);
               } catch (InterruptedException e) {
                    e.printStackTrace();
               }
                synchronized (mirror){
               System.out.println(this.girlName+" 拿着镜子");
               }
           }
       }else{
            synchronized (mirror){
              System.out.println(this.girlName+" 拿着镜子");
                try {
                    Thread.sleep(2000);
               } catch(InterruptedException e) {
                    e.printStackTrace();
               }
                synchronized (lipstick){
                  System.out.println(this.girlName+" 拿着口红");
               }
           }
       }
   }
}
public class DeadLockThread {
    public static void main(String[] args) {
        new Makeup(0,"大丫").start();
        new Makeup(1,"小丫").start();
   }
}


死锁问题的解决


死锁是由于 “同步块需要同时持有多个对象锁造成”的,要解决这个 问题,思路很简单,就是:同一个代码块,不要同时持有两个对象 锁。

/**
* 口红类
*/
    class Lipstick{
     }
/**
* 镜子类
*/
    class Mirror{
    }
/**
* 化妆线程类
*/
class Makeup extends Thread{
    private int flag; //flag=0:拿着口红。 flag!=0:拿着镜子
    private String girlName;
    static Lipstick lipstick = new Lipstick();
    static Mirror mirror = new Mirror();
    public void setFlag(int flag) {
        this.flag = flag;
      }
    public void setGirlName(String girlName)
      {
        this.girlName = girlName;
      }
    @Override
    public void run() {
        this.doMakeup();
     }
    /**
     * 开始化妆
     */
    public void doMakeup(){
        if(flag == 0){
            synchronized (lipstick){
              System.out.println(this.girlName+" 拿着口红");
                try {
                    Thread.sleep(1000);
               } catch(InterruptedException e) {
                    e.printStackTrace();
               }
           }
            synchronized (mirror){
             System.out.println(this.girlName+" 拿着镜子");
           }
       }else{
            synchronized (mirror){
              System.out.println(this.girlName+" 拿着镜子");
                try {
                    Thread.sleep(2000);
               } catch(InterruptedException e) {
                    e.printStackTrace();
               }
           }
            synchronized (lipstick){
              System.out.println(this.girlName+" 拿着口红");
           }
       }
   }
}
public class DeadLockThread {
    public static void main(String[] args) {
        Makeup makeup = new Makeup();
        makeup.setFlag(0);
        makeup.setGirlName("大丫");
        Makeup makeup1 = new Makeup();
        makeup1.setFlag(1);
        makeup1.setGirlName("小丫");
        makeup.start();
        makeup1.start();
   }
}


死锁问题的解决


死锁是由于 “同步块需要同时持有多个对象锁造成”的,要解决这个 问题,思路很简单,就是:同一个代码块,不要同时持有两个对象 锁。

/**
* 口红类
*/
     class Lipstick{
     }
/**
* 镜子类
*/
    class Mirror{
    }
/**
* 化妆线程类
*/
class Makeup extends Thread{
    private int flag; //flag = 0 :拿着口红,flag != 0 :拿着镜子
  private String girlName;
    static Lipstick lipstick = new Lipstick();
    static Mirror mirror = new Mirror();
    public Makeup(int flag,String girlName){
        this.flag = flag;
        this.girlName = girlName;
   }
    @Override
    public void run() {
        this.doMakeup();
   }
    /**
     * 开始化妆
     */
    public void doMakeup(){
        if(this.flag == 0){
            synchronized (lipstick){
               System.out.println(this.girlName+" 拿着口红");
                try {
                    Thread.sleep(1000);
               } catch(InterruptedException e) {
                    e.printStackTrace();
               }
           }
 synchronized (mirror){
              System.out.println(this.girlName+" 拿着镜子");
           }
       }else{
            synchronized (mirror){
              System.out.println(this.girlName+" 拿着镜子");
                try {
                    Thread.sleep(2000);
               } catch(InterruptedException e) {
                    e.printStackTrace();
               }
           }
            synchronized (lipstick){
              System.out.println(this.girlName+" 拿着口红");
           }
       }
   }
}
public class DeadLockThread {
    public static void main(String[] args) {
  new Makeup(0,"小丫").start();
        new Makeup(1,"大丫").start();
   }
}


线程并发协作(生产者/消费者模式)



多线程环境下,我们经常需要多个线程的并发和协作。这个时候, 就需要了解一个重要的多线程并发协作模型“生产者/消费者模式”。


角色介绍


  什么是生产者?

     生产者指的是负责生产数据的模块(这里模块可能是:方法、对 象、线程、进程)。


 什么是消费者?

   消费者指的是负责处理数据的模块(这里模块可能是:方法、对 象、线程、进程)。


 什么是缓冲区?

   消费者不能直接使用生产者的数据,它们之间有个“缓冲区”。生 产者将生产好的数据放入“缓冲区”,消费者从“缓冲区”拿要处理 的数据。


缓冲区是实现并发的核心,缓冲区的设置有两个好处:


1 实现线程的并发协作

有了缓冲区以后,生产者线程只需要往缓冲区里面放置数据,而 不需要管消费者消费的情况;同样,消费者只需要从缓冲区拿数 据处理即可,也不需要管生产者生产的情况。 这样,就从逻辑 上实现了“生产者线程”和“消费者线程”的分离,解除了生产者与 消费者之间的耦合。


2 解决忙闲不均,提高效率

生产者生产数据慢时,缓冲区仍有数据,不影响消费者消费;消 费者处理数据慢时,生产者仍然可以继续往缓冲区里面放置数据 。


实现生产者与消费者模式


创建缓冲区

/**
* 定义馒头类
*/
class ManTou{
    private int id;
    public ManTou(int id){
        this.id = id;
   }
  public int getId(){
        return this.id;
   }
}
/**
* 定义缓冲区类
*/
class SyncStack{
    //定义存放馒头的盒子
    private ManTou[] mt = new ManTou[10];
    //定义操作盒子的索引
    private int index;
    /**
     * 放馒头
     */
    public synchronized void push(ManTou manTou){
        //判断盒子是否已满
        while(this.index == this.mt.length){
            try {
                /**
                 * 语法:wait(),该方法必须要在 synchronized块中调用。
                 * wait执行后,线程会将持有的对象锁释放,并进入阻塞状态,
                 * 其他需要该对象锁的线程就可以继续运行了。
                 */
                this.wait();
               } catch (InterruptedException e){
                e.printStackTrace();
           }
       }
        //唤醒取馒头的线程
        /**
         * 语法:该方法必须要在synchronized块中调用。
         * 该方法会唤醒处于等待状态队列中的一个线程。
         */
        this.notify();
        this.mt[this.index] = manTou;
        this.index++;
   }
    /**
     * 取馒头
     */
    public synchronized ManTou pop(){
        while(this.index == 0){
            try {
                /**
                 * 语法:wait(),该方法必须要在synchronized块中调用。
                 * wait执行后,线程会将持有的对象锁释放,并进入阻塞状态,
                 * 其他需要该对象锁的线程就可以继续运行了。
                 */
                this.wait();
           } catch (InterruptedException e)
           {
                e.printStackTrace();
           }
       }
        this.notify();
        this.index--;
        return this.mt[this.index];
   }
}
public class TestProduceThread {
    public static void main(String[] args) {
   }
}


创建生产者消费者线程

/**
* 定义馒头类
*/
class ManTou{
    private int id;
    public ManTou(int id){
        this.id = id;
   }
    public int getId(){
        return this.id;
   }
}
/**
* 定义缓冲区类
*/
class SyncStack{
    //定义存放馒头的盒子
    private ManTou[] mt = new ManTou[10];
    //定义操作盒子的索引
    private int index;
    /**
     * 放馒头
     */
    public synchronized void push(ManTou manTou){
        //判断盒子是否已满
        while(this.index == this.mt.length)
          {
            try {
                /**
                 * 语法:wait(),该方法必须要在 synchronized块中调用。
                 * wait执行后,线程会将持有的对象锁释放,并进入阻塞状态,
                 * 其他需要该对象锁的线程就可以继续运行了。
                 */
                this.wait();
           } catch (InterruptedException e) {
                e.printStackTrace();
          }
       }
        //唤醒取馒头的线程
        /**
         * 语法:该方法必须要在synchronized块中调用。
         * 该方法会唤醒处于等待状态队列中的一个线程。
         */
        this.notify();
        this.mt[this.index] = manTou;
        this.index++;
   }
    /**
     * 取馒头
     */
    public synchronized ManTou pop(){
        while(this.index == 0){
            try {
                /**
                 * 语法:wait(),该方法必须要在synchronized块中调用。
                 * wait执行后,线程会将持有的对象锁释放,并进入阻塞状态,
                 * 其他需要该对象锁的线程就可以继续运行了。
                 */
                this.wait();
           } catch (InterruptedException e) {
                e.printStackTrace();
           }
       }
        this.notify();
        this.index--;
        return this.mt[this.index];
   }
}
/**
* 定义生产者线程类
*/
class ShengChan extends Thread{
    private SyncStack ss;
    public ShengChan(SyncStack ss){
        this.ss = ss;
   }
    @Override
    public void run() {
       for(int i=0;i<10;i++){
           System.out.println("生产馒头:"+i);
           ManTou manTou = new ManTou(i);
           this.ss.push(manTou);
       }
   }
}
/**
* 定义消费者线程类
*/
class XiaoFei extends Thread{
    private SyncStack ss;
    public XiaoFei(SyncStack ss){
        this.ss = ss;
   }
    @Override
    public void run() {
        for(int i=0;i<10;i++){
           ManTou manTou = this.ss.pop();
            System.out.println("消费馒头:"+i);
       }
   }
}
public class ProduceThread {
    public static void main(String[] args)
{
        SyncStack ss = new SyncStack();
        new ShengChan(ss).start();
        new XiaoFei(ss).start();
   }
}


线程并发协作总结


线程并发协作(也叫线程通信


  生产者消费者模式:


1 生产者和消费者共享同一个资源,并且生产者和消费者之间相互 依赖,互为条件。

2 对于生产者,没有生产产品之前,消费者要进入等待状态。而生 产了产品之后,又需要马上通知消费者消费。

3 对于消费者,在消费之后,要通知生产者已经消费结束,需要继 续生产新产品以供消费。

4 在生产者消费者问题中,仅有synchronized是不够的。 synchronized可阻止并发更新同一个共享资源,实现了同步但 是synchronized不能用来实现不同线程之间的消息传递(通 信)。

5 那线程是通过哪些方法来进行消息传递(通信)的呢?见如下总 结:

6 以上方法均是java.lang.Object类的方法;

都只能在同步方法或者同步代码块中使用,否则会抛出异常。


OldLu建议 在实际开发中,尤其是“架构设计”中,会大量使用这个模式。 对于初学者了解即可,如果晋升到中高级开发人员,这就是必 须掌握的内容。


目录
相关文章
|
24天前
|
安全 Java
Java多线程通信新解:本文通过生产者-消费者模型案例,深入解析wait()、notify()、notifyAll()方法的实用技巧
【10月更文挑战第20天】Java多线程通信新解:本文通过生产者-消费者模型案例,深入解析wait()、notify()、notifyAll()方法的实用技巧,包括避免在循环外调用wait()、优先使用notifyAll()、确保线程安全及处理InterruptedException等,帮助读者更好地掌握这些方法的应用。
16 1
|
1月前
|
消息中间件 NoSQL 关系型数据库
【多线程-从零开始-捌】阻塞队列,消费者生产者模型
【多线程-从零开始-捌】阻塞队列,消费者生产者模型
23 0
|
2月前
|
存储 Java 程序员
优化Java多线程应用:是创建Thread对象直接调用start()方法?还是用个变量调用?
这篇文章探讨了Java中两种创建和启动线程的方法,并分析了它们的区别。作者建议直接调用 `Thread` 对象的 `start()` 方法,而非保持强引用,以避免内存泄漏、简化线程生命周期管理,并减少不必要的线程控制。文章详细解释了这种方法在使用 `ThreadLocal` 时的优势,并提供了代码示例。作者洛小豆,文章来源于稀土掘金。
|
3月前
|
消息中间件 设计模式 安全
多线程魔法:揭秘一个JVM中如何同时运行多个消费者
【8月更文挑战第22天】在Java虚拟机(JVM)中探索多消费者模式,此模式解耦生产与消费过程,提升系统性能。通过`ExecutorService`和`BlockingQueue`构建含2个生产者及4个消费者的系统,实现实时消息处理。多消费者模式虽增强处理能力,但也引入线程安全与资源竞争等挑战,需谨慎设计以确保高效稳定运行。
93 2
|
2月前
|
安全 Java
LinkedBlockingQueue 是线程安全的,为什么会有两个线程都take()到同一个对象了?
LinkedBlockingQueue 是线程安全的,为什么会有两个线程都take()到同一个对象了?
44 0
|
3月前
|
安全 Java C#
Spring创建的单例对象,存在线程安全问题吗?
Spring框架提供了多种Bean作用域,包括单例(Singleton)、原型(Prototype)、请求(Request)、会话(Session)、全局会话(GlobalSession)等。单例是默认作用域,保证每个Spring容器中只有一个Bean实例;原型作用域则每次请求都会创建一个新的Bean实例;请求和会话作用域分别与HTTP请求和会话绑定,在Web应用中有效。 单例Bean在多线程环境中可能面临线程安全问题,Spring容器虽然确保Bean的创建过程是线程安全的,但Bean的使用安全性需开发者自行保证。保持Bean无状态是最简单的线程安全策略;
|
3月前
|
NoSQL Redis
Lettuce的特性和内部实现问题之在同步调用模式下,业务线程是如何拿到结果数据的
Lettuce的特性和内部实现问题之在同步调用模式下,业务线程是如何拿到结果数据的
|
1月前
|
存储 消息中间件 资源调度
C++ 多线程之初识多线程
这篇文章介绍了C++多线程的基本概念,包括进程和线程的定义、并发的实现方式,以及如何在C++中创建和管理线程,包括使用`std::thread`库、线程的join和detach方法,并通过示例代码展示了如何创建和使用多线程。
43 1
C++ 多线程之初识多线程
|
24天前
|
Java 开发者
在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口
【10月更文挑战第20天】在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口。本文揭示了这两种方式的微妙差异和潜在陷阱,帮助你更好地理解和选择适合项目需求的线程创建方式。
18 3
|
24天前
|
Java 开发者
在Java多线程编程中,选择合适的线程创建方法至关重要
【10月更文挑战第20天】在Java多线程编程中,选择合适的线程创建方法至关重要。本文通过案例分析,探讨了继承Thread类和实现Runnable接口两种方法的优缺点及适用场景,帮助开发者做出明智的选择。
16 2

相关实验场景

更多