黑马程序员-多线程

Java线程创建与同步

---------------------- ASP.Net+Android+IOS开发、.Net培训、期待与您交流! ----------------------

创建线程的两种方式:
继承Thread类,用代码体现:

public class MyThread extends Thread
   {
    public void run()
    {
     for(int x=0; x<100; x++)
     {
      System.out.println(getName()+"---"+"hello"+x);
     }
    }
   }

   public MyThreadTest
   {
    public static void main(String[] args)
    {
     MyThread my1 = new MyThread();
     MyThread my2 = new MyThread();

     my1.start();
     my2.start();
    }
   }

实现Runnable接口
1.定义类实现Runnable接口
2.覆盖Runnable接口中的run方法

用代码体现
   public class MyRunnable implements Runnable
   {
    public void run()
    {
     for(int x=0; x<100; x++)
     {
      System.out.println(Thread.currentThread().getName

()+"---"+"hello"+x);
     }
    }
   }
   
   public class MyRunnableTest
   {
    public static void main(String[] args)
    {
     MyRunnable my = new MyRunnable();

     Thread t1 = new Thread(my);
     Thread t2 = new Thread(my);

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

注意:复写run方法的目的是将自定义的代码存储在run方法中,让线程运行
将线程要运行的代码存放在该run方法中
3.通过Thread类建立线程对象
4.通过Runnable接口的子类对象作为实际参数传递给Thread类的构造函数
为什么呢?因为自定义的run方法所属的对象是Runnable接口的子类对象,所以要
让线程去指定指定对象的run方法。就必须明确该run方法所属对象
5.调用Thread类的start方法开启线程并调用Runnable接口子类的run方法
start方法有两个作用:
一是启动线程,二是调用run方法
线程有自己默认的名称:
格式:Thread-编号,编号从0开始。
static Thread currentThread():获取当前线程对象
getName():获取线程名称
设置线程名称:setName或者构造函数
实现方式和继承方式有什么区别呢?
实现方式好处是:避免了单继承的局限性,建议使用它
继承方式:线程代码存放在Thread子类run()方法中
实现方式:存在接口的子类的run方法中
线程安全:
我们先来看段代码:
package thread;

public class TicketsRunnable implements Runnable
{
private int tickets=200;
public void run()
{
  while(true)
  {
   if(tickets>0)
   {
    System.out.println(Thread.currentThread().getName()+"....sale:"+tick--);

   }
  }
}

}

package thread;

public class TicketDemo
{
public static void main(String[] args)
{
  TicketsRunnable t=new TicketsRunnable();
 
  Thread t1=new Thread(t);
  Thread t2=new Thread(t);
  Thread t3=new Thread(t);
  Thread t4=new Thread(t);

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

}
分析:
在判断中,假如tickets大于1,满足条件,所以Thread-1准备去执行,但是有可能出现一种情况,就是Thread-1
刚判断完正要执行的时候,但是被线程Thread-2给抢去了,而Thread-2正准备要执行,但是被Thread-3抢去了,Thread-3正要准备
去执行的时候,但是被Thread-4给抢去了,这四个全部挂着,但是它们都有执行的资格,假设当Thread-2,Thread-3,Thread-4全部挂着的时候
切换到Thread-1,它就买到1号票了,其他的线程因为不要再判断了,所以他们买到的票tick--就分别是0,-1,-2张错票,这显然不对,所以这里线程不安全。
造成这个问题的原因:
当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,
另一个线程参与进来执行,导致共享数据的错误
解决办法:
对多条操作共享数据的语句,只能让一个都执行完,在执行过程中,其他线程不能参与进来
Java对于多线程安全问题使用同步代码块来解决:
synchronized(对象)
{
     需要被同步的代码    
}
哪些语句正在操作共享数据,那哪些代码块就需要被同步,如下代码所示:
package thread;

public class TicketetsRunnable implements Runnable
{
private int tickets=1000;
Object obj=new Object();
public void run()
{
  while(true)
  {
   synchronized(obj)
   {
    if(tick>0)
    {
     try {
      Thread.sleep(100);
     } catch (InterruptedException e) {
     
     }
     System.out.println(Thread.currentThread().getName()+"....sale:"+(tickets--));
         }
    }
  }
}

}
同步代码块的原理:
用锁的思想去理解
对象如同锁,持有锁的线程可以在同步中执行,没有锁的线程即使获取cpu的执行权,也进不去,因为没有获取锁。
同步的前提:
1.必须要有两个或者两个以上的线程
2.必须是多个线程使用同一个锁
必须保证同步中有一个线程在运行就可以了
弊端:多个线程需要判断锁,较为消耗资源
多线程-同步函数:
如何同步?
1.明确哪些代码是多线程运行代码
2.明确共享数据
3.明确多线程运行代码中哪些语句是操作共享数据的
在函数的返回值前面加上synchronized,它就变成同步函数了
同步函数用的是哪一个锁呢?
函数需要被对象调用,函数都有一个所属对象的引用,那就是this
所以同步函数使用的锁是this。
如果同步函数被静态修饰后,使用的锁是什么呢?
通过验证,发现不是this。因为静态方法中也不可以定义this。
静态进内存时,内存中没有本类对象,但是一定有该类对应的字节码文件对象,所以它的锁可以用字节码文件对象
格式:类名.class。
该对象的类型是Class.
单例设计模式:
饿汉式:
class Single
{
    private static final Single s=new Single();
    private Single(){}
    public static Single getInstance()
{
      return s;
  }
}
懒汉式:
class Single
{
    private static final Single s=null;
    private Single(){}
    public static synchronized Single getInstance()
    {
         if(s==null)
               s=new Single();
         return s;
}

class SingleDemo
{
     public static void main(String[] args)
     {
           System.out.println("Hello World");


class Single2
{
    private static final Single2 s=null;
    private Single2(){}
    public static  Single getInstance()
    {
         if(s==null)
         {
             synchronized(Single2.class)
             {
                 if(s==null)
                 s=new Single();
         return s;
}

class SingleDemo
{
     public static void main(String[] args)
     {
           System.out.println("Hello World");

懒汉式面试经常问到。
第二种方式效率提高了。
单例设计模式涉及的知识点必须要会!。
线程间通信,其实就是多个线程在操作同一个资源。

---------------------- ASP.Net+Android+IOS开发、.Net培训、期待与您交流! ----------------------

内容概要:本文详细比较了GPU、TPU专用AI芯片在大模型推理优化方面的性能、成本及适用场景。GPU以其强大的并行计算能力和高带宽显存,适用于多种类型的神经网络模型和计算任务,尤其适合快速原型开发和边缘计算设备。TPU专为机器学习设计,擅长处理大规模矩阵运算密集型任务,如Transformer模型的推理,具有高吞吐量和低延迟特性,适用于自然语言处理和大规模数据中心的推理任务。专用AI芯片通过高度定制化架构,针对特定神经网络模型进行优化,如卷积神经网络(CNN),在处理特定任务时表现出色,同时具备低功耗和高能效比的优势,适用于边缘计算设备。文章还介绍了各自的优化工具和框架,如CUDA、TensorRT、TPU编译器等,并从硬件成本、运营成本和开发成本三个角度进行了成本对比。 适合人群:从事人工智能、深度学习领域的研究人员和技术人员,尤其是对大模型推理优化感兴趣的读者。 使用场景及目标:①帮助读者理解GPU、TPU和专用AI芯片在大模型推理中的优缺点;②为选择适合的硬件平台提供参考依据,以实现最优的推理性能和成本效益;③介绍各种优化工具和框架,帮助开发者高效部署和优化模型。 其他说明:本文不仅涵盖了硬件架构特性,还深入探讨了优化技术和应用场景,旨在为读者提供全面的技术参考。在选择硬件平台时,需综合考虑具体任务需求、预算限制及开发资源等因素。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值