Java多线程

1 多线程的概念

(1)并发:同一时间段内完成多件事情,使用分时复用的原理,例如一个CPU在多个任务之间来回切换;

         1)对于java虚拟机而言,不管CPU是单核还是多核,都是使用并发的方式,例如java代码开启多个线程,这多个线程就是并发的,分析的时候需要使用考虑到线程安全问题。

(2)并行:同一时刻完成多件事情,多个资源单独处理每件事情,例如多核CPU,一个核心处理一个任务。

 2 多线程的执行原理

(1)创建Thread类或其子类对象,获取开辟线程的方法

(2)调用start()方法,会在内存中创建一个该新线程的栈空间,用来执行新线程的代码 

 3 Thread类

(1)Thread类是线程相关的类,主要用来开启新线程,设置线程的参数,获取线程信息等功能

(2)Thread类的常用方法

       构造方法

         1)public Thread() :分配一个新的线程对象。
         2)public Thread(String name) :分配一个指定名字的新的线程对象。
         3)public Thread(Runnable target) :分配一个带有指定目标新的线程对象,也就是传递一个Runnable接口子实现类。
         4)public Thread(Runnable target,String name) :分配一个带有指定目标新的线程对象(Runnable接口实现类)并指定名字

         常用方法

              1)public String getName() :获取当前线程名称。
              2)public void start() :使此线程开始执行; Java虚拟机调用此线程的run方法。
              3)public void run() :此线程要执行的任务在此处定义代码。
              4)public static void sleep(long millis) :使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行)。
              5)public static Thread currentThread() :返回对当前正在执行的线程对象的引用
 

 4 创建线程的方式

 (1)创建一个继承Thread类的子类,重写run()方法,创建该子类对象并调用start()执行新线程;

 (2)创建Runnable接口的实现类,new一个Thread类对象,将Runnable实现类作为参数传递给Thread构造方法,并调用start()方法开启线程

(3)使用匿名内部类的方式实现上面两种创建线程的方法

        1)匿名内部类-Thread子类

new Thread(){
 @Override
 public void run() {
   //线程执行代码          
 }
}.start();

        2)匿名内部类-Runnable接口

 new Thread(new Runnable() {
     @Override
     public void run() {
         //线程执行代码      
     }
 }).start();

 (4)Thread和Runnable两种创建方式的区别

        1)Thread通过产生其子类,重写子类中的run()方法来实现新线程的调用,不适合资源的共享,例如共享线程执行方法,使用Runnable可以很容易实现资源的共享(不同线程使用同一个接口实现类),所以实际使用一般使用Runnable方式实现

        2)Runnable实现新线程的方式的优点汇总

            1)Runnable方式容易实现资源的共享,通过多个线程使用同一个接口实现类实现

            2)Runnable方式代码的耦合性更低,编译代码的修改维护

            3)在使用线程池的时候,只能放入实现Runnable或则是Callable类的线程,不能直接放入Thread

            4) 避免单继承的局限性

5 线程安全

(1)在使用多线程的时候,如果过个线程对同一个资源(数据)机型读写的时候,就容易发生线程安全问题;

例子:线程1在对一个数据合法性判断后,刚要操作数据时被切换到线程2,线程2也对数据进行操作,导致数据变得不符合线程1判断,此时cpu切回线程1时就会对不符合线程1要求的数据进行操作,从而产生问题。

(2)避免线程安全的方法

       1)线程同步:一个代码还没有被一个线程执行完,不允许其他线程执行此代码,从而保证要同步代码执行的原子性;

       2)具体实现方式

           1)同步代码块:使用synchronized关键字修饰一个代码块,该代码块中的内容就是同步代码

                 1)锁,可以是任意类型对象,但是多个代码块同步,需要保证使用同一个锁;

//同步代码块1
synchronized(同步锁a){
  //需要同步操作的代码
}

....
//同步代码块2
synchronized(同步锁a){//两个代码块是同步的,必须使用同一个锁
  //需要同步操作的代码
}

           2)同步方法:使用synchronized关键字修饰的方法(比较少用)

public synchronized void method(){
    //可能会产生线程安全问题的代码
}

           3)lock锁:Java一个接口java.util.concurrent.locks.Lock ,(一般使用其实现类ReentrrantLock)提供了比同步代码块和同步方法更加广泛的操作

                1)实现锁方法

                      1)public void lock() :加同步锁。
                      2)public void unlock() :释放同步锁。

6 线程的运行状态

(1)在线程的这个生命周期中,有6中状态,分别是新建态、可执行态、无限等待态、计时等待态、锁阻塞态、终止态

(2)状态之间的切换

(3)多线程状态涉及的常用方法

       1)wait()/wait(time):使用锁调用,并且要在同步代码块中调用,使当前线程进入等待态,带参方法时间到了还没有被notify唤醒,也会自动唤醒;

       2)notify():使用锁调用,并且要在同步代码块中调用,唤醒同一个锁下的等待线程中的一个线程;

       3)notifyAll():使用锁调用,必须使用同步代码块,唤醒同一个锁下的所有等待线程;

       4)sleep():使线程进入等待态,时间到才能唤醒;

(4)sleep()和wait()方法的区别

         1)  sleep()进入等待态后,不会释放锁,如果在同步代码块中使用该方法,则其他线程在该线程等待期间也不能执行该方法

         2)sleep是Thread类的方法,wait是Object的方法,也就是所有的对象都可以调用;

         3)wait必须在同步代码块中使用锁调用,sleep没有限制。

 

7 多线程通信——等待唤醒机制

(1)多线程之间的通信

       1)当多线程之间的协作完成一件任务的时候,需要线程间通信,例如一个线程完成数据的产生,一个线程完成数据的获取,这个就要涉及到操作的先后问题,先要有数据才能去取。这就涉及线程之前的通信

       2)常用的线程通信方式是等待唤醒机制,等待就是线程调用wait进入等待态,放弃CPU执行权,唤醒就是当需要一个任务来执行的时候,使用notify唤醒任务。例如生产者在生产完数据,就会唤醒消费者来获取数据,自己进入等待态,消费者消费完数据后,就会唤醒生产者进行数据生产,然后自己进入等待态,以此过程进行循环;

       3)使用等待唤醒机制注意事项

             1)必须使用同一个锁调用wait和notify

             2)等待唤醒必须在同步代码块中执行,因为必须通过锁调用等待和唤醒方法

8 线程池

(1)线程池就是一个装有多个线程的容器,通过该容器获取线程,可以降低频繁开启和关闭线程的资源消耗

(2)线程池的好处

        1)减少资源消耗:通过线程池获取线程,可以通过线程的复用,减少频繁开启和关闭线程的资源消耗;

        2)便于管理线程:可以更方便对线程进行管理,例如可以根据系统来选择线程池中线程数量;

        3)提高响应速度:需要创建新线程的时候,可以直接从线程中获取。

(3)线程池的相关类

        1)java线程池中提供了相关的接口和类来支持线程池的使用

              1)java.util.concurrent.Executor是线程池的顶级接口,但只是提供了一些执行方法,并不算真正的线程池接口

              2)java.util.concurrent.ExecutorService是线程池的接口,常用方法

                    public Future<?> submit(Runnable task),用来获取线程池中的某一对象并执行

              3)java.util.concurrent.Executors:是一个工程类,用例产生各种线程池,常用的方法是

                   public static ExecutorService newFixedThreadPool(int nThreads),创建一个有界线程池,创建时需要指定线程数量

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值