JAVA多线程(一) Thread & Runnable

时间:2022-05-17 22:48:51

githut代码地址:https://github.com/showkawa/springBoot_2017/tree/master/spb-demo/spb-brian-query-service/src/main/java/com/kawa/thread

1.实现方式

1.继承Thread类  (重写run()方法,通过start()方法来执行线程)
2.实现Runnable接口
3.使用匿名内部类方式创建

2.多线程常用API

常用线程api方法  
start() 启动线程
currentThread() 获取当前线程对象
getID() 获取当前线程ID Thread-编号 该编号从0开始
getName() 获取当前线程名称
sleep(long mill) 休眠线程
Stop() 停止线程,
常用线程构造函数  
Thread() 分配一个新的 Thread 对象
Thread(String name) 分配一个新的 Thread对象,具有指定的 name正如其名。
Thread(Runable r) 分配一个新的 Thread对象
Thread(Runable r, String name) 分配一个新的 Thread对象

3.多线程的运行状态

新建状态


new Thread(r),线程还没有开始运行,此时线程处在新建状态。

就绪状态


当线程对象调用start()方法即启动了线程,并调度线程运行run()方法。当start()方法返回后,线程就处于就绪状态。处于就绪状态的线程并不一定立即运行run()方法,
线程还必须同其他线程竞争CPU时间,只有获得CPU时间才可以运行线程。

运行状态


当线程获得CPU时间后,它才进入运行状态,真正开始执行run()方法.

阻塞状态


线程运行过程中,可能由于各种原因进入阻塞状态
   1>线程通过调用sleep方法进入睡眠状态
   2>线程调用一个在I/O上被阻塞的操作,即该操作在输入输出操作完成之前不会返回到它的调用者
   3>线程试图得到一个锁,而该锁正被其他线程持有
   4>线程在等待某个触发条件

死亡状态


有两个原因会导致线程死亡:
 1) run方法正常退出而自然死亡,
 2) 一个未捕获的异常终止了run方法而使线程猝死。
为了确定线程在当前是否存活着(就是要么是可运行的,要么是被阻塞了),需要使用isAlive方法。如果是可运行或被阻塞,这个方法返回true;
如果线程仍旧是new状态且不是可运行的, 或者线程死亡了,则返回false.

4. join()方法作用

join作用是让其他线程变为等待,    
thread.join();// 让其他线程变为等待,直到当前t1线程执行完毕,才释放。
thread.Join把指定的线程加入到当前线程,可以将两个交替执行的线程合并为顺序执行的线程。比如在线程B中调用了线程A的Join()方法,直到线程A执行完毕后,
才会继续执行线程B。

5.线程同步

5.1 synchronized

5.1.1 同步方法

 

即有synchronized关键字修饰的方法。 由于java的每个对象都有一个内置锁,当用此关键字修饰方法时, 内置锁会保护整个方法。
在调用该方法前,需要获得内置锁,否则就处于阻塞状态。

注: synchronized关键字也可以修饰静态方法,此时如果调用该静态方法,将会锁住整个类。

5.1.2 同步代码块

即有synchronized关键字修饰的语句块。 被该关键字修饰的语句块会自动被加上内置锁,从而实现同步 代码如:
synchronized(object){....}

注:同步是一种高开销的操作,因此应该尽量减少同步的内容。通常没有必要同步整个方法,使用synchronized代码块同步关键代码即可。

5.2 wait与notify
wait()、notify()、notifyAll()是三个定义在Object类里的方法,可以用来控制线程的状态。
这三个方法最终调用的都是jvm级的native方法。随着jvm运行平台的不同可能有些许差异。
如果对象调用了wait方法就会使持有该对象的线程把该对象的控制权交出去,然后处于等待状态。
如果对象调用了notify方法就会通知某个正在等待这个对象的控制权的线程可以继续运行。
如果对象调用了notifyAll方法就会通知所有等待这个对象控制权的线程继续运行。
注意:一定要在线程同步中使用,并且是同一个锁的资源
5.3 wait 与sleep区别
1.wait 用于同步中,可以释放锁的资源
  sleep不会释放锁的资源
2.wait需要notify才能从休眠状态变为运行状态
  sleep时间到期,从休眠状态变为运行状态

6. JDK1.5 Lock锁

6.1 Lock写法

Lock lock  = new ReentrantLock();
lock.lock();
try{
//可能会出现线程安全的操作
}finally{
//一定在finally中释放锁
//也不能把获取锁在try中进行,因为有可能在获取锁的时候抛出异常
  lock.ublock();
}

6.2 Lock 接口与 synchronized关键字的区别

Lock 接口可以尝试非阻塞地获取锁 当前线程尝试获取锁。如果这一时刻锁没有被其他线程获取到,则成功获取并持有锁。
Lock 接口能被中断地获取锁 与 synchronized 不同,获取到锁的线程能够响应中断,当获取到的锁的线程被中断时,中断异常将会被抛出,同时锁会被释放。
Lock 接口在指定的截止时间之前获取锁,如果截止时间到了依旧无法获取锁,则返回。

6.3 Condition用法

 Condition的功能类似于在传统的线程技术中的,Object.wait()和Object.notify()的功能。
 
 Condition condition = lock.newCondition();
 res. condition.await();  类似wait
 res. Condition. Signal() 类似notify