Java多线程系列(一)—多线程基础
2017-10-13 18:13
330 查看
Java多线程系列(一)—多线程基础
线程是CPU调度的最小单元,单核时代多线程可以在IO密集型操作时有更高的效率,在如今这个多核为主的时代,多线程更能有效的发挥多核的优势,充分利用CPU资源;个人主页:tuzhenyu’s page
原文地址:Java多线程系列(一)—多线程基础
1. 线程基础
(1) 线程和进程
进程是系统资源分配的基本单位,线程是CPU资源调度的最小单元,一个进程下可以有多个线程;每个进程都有各自独立的地址空间,所有进程共享父进程的地址空间;
进程上下文切换的开销远远大于线程的上下文切换
(2) 线程的创建
调用Java程序入口的public void static main(){}的是一个由JVM默认创建的名称叫做main的线程继承Tread类创建线程,线程的启动需要通过Thread.start()调用,会通过本独方法的调用让操作系分配CPU资源,JVM中的Thread对象只是线程的外壳;
Public class MyThread extends Tread{ @override pulic void run(){ super.run(); //继承Thread类的run()方法 } } Public class Run { public static void main(){ MyThread myThread = new MyThread(); myThread.start(); } }
实现Runnabale接口创建线程,实现Runnable的实例化对象作为参数传入Thread中设置到一个名为”target”的属性上,Thread默认的Run是调用这个target的run()方法来完成;
Public class MyRunnable implements Runnable{ pulic void run(){ System.out.println("hello world") } } Public class Run { public static void main(){ MyRunnable myRunnable = new MyRunnable(); MyThread myThread = new MyThread(myRunnable); myThread.start(); } }
通过Thead创建线程和通过Runable创建线程区别
通过Thead创建线程需要继承Thread类重写run()方法,线程运行时直接执行继承类的run方法;
通过Runnable创建线程需要实现Runnable接口,并将实现类当做参数注入到Thread类的target中,线程运行时会运行Thread类的run()方法查看对应target是否为空,如果不为空则调用target的run()方法;
@Override public void run() { if (target != null) { target.run(); } }
- Thread实现只能继承一个类,Runnable接口可以实现多个接口,在需要多继承的情境下使用Runnable接口实现
(3) 线程的状态
NEW(新建状态):new了一个新的线程对象,还未调用start()Runnable(可运行状态):包含Ready就绪状态和Running运行状态
就绪状态:其他线程调用了该对象的start()方法,等待获取CPU的使用权
运行状态:获取了CPU的使用权,执行run()程序
Block(阻塞状态):通常是因为等待锁造成线程挂起,JVM会把该线程置为阻塞状态
Waiting(等待状态):执行Object.wait()方法后所处的等待状态,需要其他线程通知或者中断
Time_Waiting(超时等待状态):执行Thread.sleep(n)线程睡眠挂起,进入超时等待状态;
Terminated(终止态):执行完run()方法后线程的状态;
(4) 线程的优先级
Java中优先级分为1~10等级,默认main的等级为5线程优先级具有继承性,若B的优先级未明确设置,A线程启动B线程,则B线程的优先级与A是一样的
2. 线程常用方法
(1) Thread类的常用方法
静态方法
Thread.currentThread()方法:获取当前线程Thread.currentThread().getName() // 获取线程名 Thread.currentThread().getId() // 获取线程唯一标识
sleep():让该正在执行的线程休眠指定毫秒数
this.currentThread().sleap(2000) //休眠2秒
yield()线程让步
Thread.yield(); //当前线程进行让步,放弃CPU资源后重新竞争,如果竞争失败则从运行态度转换为阻塞态;
intercepted(),isIntercepted()线程停止判断
实例方法
start():启动线程,进入就绪状态等待获取CPU资源run():mian线程调用Thread.run()方法,代码还是同步顺序执行
isAlive()方法:判断当前的线程是否处于活动状态(就绪状态,运行状态)
myThread.isAlive() //判断线程是否处于存活状态
intercept()线程停止
myThread.intercept(); //将myThread线程标记为停止态
join()线程等待
myThread.join(); //当前线程等待myThread线程执行完后再执行
(2) 线程的停止
线程停止的方法:当run()方法完成后线程终止
使用Thread.stop()方法强行终止当前线程
使用Thread.interrupt()方法中断当前线程
interrupt()+interruptted+break
interrupt()+interruptted+return
interrupt()+interruptted+throw Exception
sleep()和wait()方法+interrupt()抛出InterruptedException异常
class MyThread extends Thread { @Override public void run() { System.out.println("run:"+ System.currentTimeMillis()); super.run(); for (int i=0;i<200;i++){ if(this.interruptted){ break; } System.out.println("i:"+i); } } } public class ThreadStopTest { public static void main(String[] args) throws InterruptedException{ MyThread myThread = new MyThread(); myThread.start(); System.out.println("start:"+System.currentTimeMillis()); Thread.sleep(2000); //main主线程休眠,让出CPU使用权给myThread线程,不然会执行完main再让出使用权 System.out.println("sleep:"+System.currentTimeMillis()); myThread.interrupt(); System.out.println("interrupt:"+System.currentTimeMillis()); } }
判断线程停止状态:
this.interrupted():测试当前线程是否已经是中断状态,执行后清除状态标志
this.isInterrupted():测试当先线程对象是否已经中断,但不清除状态标志
suspend()和resume():可能会出现独占公共同步对象,也会出现因为暂停造成的不同步现象
(3) 线程的让步
线程的让步可以通过yield(),sleep(0),sleep(1)实现sleep(0),sleep(1)和yelid()实现线程让步区别
sleep(0)线程进入就绪状态,但是只允许优先级更高的线程使用CPU,如果没有合适的线程该线程会重新获取到时间片
sleep(1)线程睡眠1ms后进入就绪状态,各个线程公平抢占CPU
yelid()线程让出CPU进入就绪状态,并且和其他线程公平竞争CPU
线程让步Thread.yield()是通过本地方法(native)实现的
(4) 线程的等待
Thread.join()的使用:一个线程A执行了thread.join()表式线程A要等待线程thread运行结束后才能从thread.join()中返回继续执行后面的代码。//全部开启线程后执行线程等待 public static void main(String[] args) throws Exception{ Thread[] threads = new Thread[5]; for (int i=0;i<5;i++){ threads[i] = new Thread(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getId()+" is run"); } }); } for (int i=0;i<5;i++){ threads[i].start(); } for (int i=0;i<5;i++){ threads[i].join(); } System.out.println("finish"); }
线程等待join()方法实现原理
join()方法加有对象锁,锁的对象就是被等待的线程;在方法内循环判断被等待线程是否存活,如果存活则调用wait()方法进入阻塞状态等待被通知;当被等待线程结束时会做清理工作,其中包括一项就是通知唤醒等待该线程对象锁的线程;因此join()方法是通过对象锁实现的;
public final synchronized void join(long millis) throws InterruptedException { long base = System.currentTimeMillis(); long now = 0; if (millis < 0) { throw new IllegalArgumentException("timeout value is negative"); } if (millis == 0) { while (isAlive()) { wait(0); } } else { while (isAlive()) { long delay = millis - now; if (delay <= 0) { break; } wait(delay); now = System.currentTimeMillis() - base; } } }
(4) 线程的wait/notify通信机制
class Thread1 extends Thread{ private Object object; public Thread1(Object object){ this.object = object; } @Override public void run() { try{ synchronized (object){ System.out.println("begin to wait:"+Thread.currentThread().getName()); object.wait(); System.out.println("wait end:"+Thread.currentThread().getName()); } }catch (InterruptedException e){ e.printStackTrace(); } } } class Thread2 extends Thread{ private Object object; public Thread2(Object object){ this.object = object; } @Override public void run() { synchronized (object){ System.out.println("begin to notify:"+Thread.currentThread().getName()); object.notify(); System.out.println("notify end:"+Thread.currentThread().getName()); } } } public class WaitNotifyTest { public static void main(String[] args) throws InterruptedException{ Object o = new Object(); Thread1 thread1 = new Thread1(o); thread1.start(); Thread.sleep(2000); Thread2 thread2 = new Thread2(o); thread2.start(); } }
wait()和notify()必须在同步块中调用,wait()和notify()必须持有同一对象锁,这样才能wait()释放对象锁后notify()持有该对象锁;wait()应该先持有对象锁,执行wait()方法后释放锁,其他线程竞争该对象锁;
调用wait()的线程将进入Waiting状态,只有等待其他线程通知或者被中断才返回;wait()方法底层调用wait(0)表示一直等待直到被其他线程唤醒;
wait(long)方法:等待某一时间内是否有线程进行唤醒,超出这个时间会自动唤醒,如果未竞争得到CPU资源则进入阻塞Blocked状态;
notify()方法用来通知wait状态的线程,如果有多个持有相同对象锁的线程,随机挑选一个发出通知notify
执行完notify()方法之后,当前线程不会马上释放该对象锁,要执行完synchronized代码块内的程序后才能释放
notifyAll()方法:唤醒所有处于当前对象锁的wait状态的线程
总结
线程的方法一般是通过调用本地方法将具体操作交由操作系统执行,线程让步join()方法的实现是通过对象锁;a3ef
相关文章推荐
- javaSE_8系列博客——重要的基础Java类——多线程--2--进程和线程
- java 多线程系列基础篇(五)之线程等待与唤醒
- java 多线程系列基础篇(四)之 synchronized关键字
- java 多线程系列基础篇(九)之interrupt()和线程终止方式
- Java多线程系列--【基础篇07】- 线程休眠
- Java多线程干货系列—(一)Java多线程基础
- Java的多线程机制系列:(一)总述及基础概念
- [转]Java多线程干货系列—(一)Java多线程基础
- Java的多线程机制系列:(一)总述及基础概念
- java 多线程系列基础篇(二)
- java 多线程系列基础篇(三)之start()和run()的区别
- java 多线程系列基础篇(七)之线程休眠
- 【java基础总结系列】:java 多线程3种实现方式
- java多线程系列(一)基础概念
- java 多线程系列基础篇(十一)之生产消费者问题
- Java多线程系列--【基础篇02】- 常用的实现多线程的两种方式
- Java多线程干货系列(1):Java多线程基础
- Java多线程干货系列—(一)Java多线程基础
- Java多线程干货系列—(一)Java多线程基础
- 教你学会java基础多线程系列文章之中级篇(一)