Java多线程(二)认识Java里面的Thread
来源:互联网 发布:java 获取对象的大小 编辑:程序博客网 时间:2024/05/21 15:24
转载请注明出处:http://blog.csdn.net/github_39430101/article/details/77340996
创建线程的三种方法
java.lang.Thread类是线程类,其每一个实例表示一个可以并发运行的线程。我们可以通过继承该类并重写run方法来定义一个具体的线程。其中重写run方法的目的的定义该线程要执行的逻辑。启动线程时调用线程的start()方法而非直接调用run()方法。start()方法会将当前线程纳入线程调度,使当前线程可以开始并发运行。当线程获取时间片段后会自动开始执行run方法中的逻辑。
继承Thread类
public class TestThread extends Thread{ @Override public void run(){ for(int i=0; i<100; i++){ System.out.println("我是线程"); } }}
创建和启动线程:
public class ThreadApp{ public static void main(String[] args){ Thread thread = new TestThread(); //实例化线程 thread.start(); //启动线程 }}
实现Runnable创建并启动线程
实现Runnable接口并重写run()方法来定义线程体,然后再创建线程的时候讲Runnable的的实例传入并启动线程。这样做的好处在于可以将线程与线程要执行的任务分离开减少耦合,同时Java是单继承的,定义一个类实现Runnable接口这样的做法可以更好的去实现其他父类或接口。因为接口是多继承关系。这里我们讲一下静态代理设计模式。
静态代理
- 真实角色
- 代理角色 :持有真实角色的引用
- 二者实现相同的接口
public class StaticProxy { public static void main(String[] args) { //创建真实角色 You you = new You(); //创建代理角色+真实角色的引用 Agency agency = new Agency(you); agency.renting(); }}//创建一个租房的接口,里面有租房方法interface Rent{ //公共方法租房 void renting();}//真实角色class You implements Rent{ @Override //租房 public void renting(){ System.out.println("我租房子"); }}//代理角色,中介公司class Agency implements Rent{ Rent you; public Agency(){ } public Agency(Rent you){ this.you = you; } //租房前要做的 private void before(){ System.out.println("找中介公司"); } private void after(){ System.out.println("交房租"); } @Override public void renting(){ before(); you.renting(); after(); }}//输出:找中介公司我租房子交房租
Runnable相当于我们的租房接口,Thread类也是实现它的,我们只需要实现它并重写run()方法,其他的事情交给中介Thread类
//真实角色类public class TestRunnable implements Runnable{ @Override public void run(){ for(int i=0; i<100; i++){ System.out.println("我是线程"); } }}
启动线程
public class ThreadApp{ public static void main(String[] args){ Runnable runnable = new TestRunnable(); Thread thread = new Thread(runnable); //实例化线程并传入线程体 thread.start(); //启动线程 }}
实现Callable接口
Callable是类似于Runnable的接口,实现Callable接口的类和实现Runnable的类都是可被其他线程执行的任务。Callable和Runnable有几点不同:
- Callable规定的方法是call(),而Runnable规定的方法是run()
- call()方法可抛出异常,而run()方法是不能抛出异常的
- Callable的任务执行后可返回值,运行Callable任务可拿到一个Future对象,而Runnable的任务是不能返回值的。Future标识异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并检索计算的结果。通过Future对象可了解任务执行情况,可取消任务的执行,还可获取任务执行的结果。
public class Call { public static void main(String[] args) { Callable<Integer> callable = new Callable<Integer>() { public Integer call() throws Exception { return new Random().nextInt(100); } }; FutureTask<Integer> future = new FutureTask<Integer>(callable); new Thread(future).start(); try { Thread.sleep(5000); System.out.println(future.get()); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } }}
线程API
Thread的静态方法currentThread方法可以用于获取运行当前代码片段的线程。
Thread current = Thread.currentThread();
获取线程信息
long getId() //返回该线程的标识符String getName() //返回该线程的名称int getPriority() //返回线程的优先级Thread.state getState() //获取线程的状态boolean isAlive() //测试线程是否处于活动状态boolean isDaemon() //测试线程是否为守护线程boolean isInterrupted() //测试线程是否已经中断
常用方法:
void run() //创建该类的子类时必须实现的方法void start() //开启线程的方法static void sleep(long t) //释放CPU的执行权,不释放锁。调用的目的是不让当前线程霸占该进程所获取的CPU资源,以留一定的时间给其他线程执行的机会final void wait() //释放CPU的执行权,释放锁。当一个线程执行到wait()方法是,它就进入到一个和该对象相等的等待池(Waiting Pool)中,同时失去了对象的锁-暂时的,wait后还要返还对象锁。当前线程必须拥有对前对象的锁,如果当前线程不是此锁的拥有者,会抛出IllegalMonitorStateException异常,所以wait()必须在synchronized block中调用final void notify()/notifyAll() //唤醒在当前对象等待池中等待的第一个线程/所有线程。notify/notifyAll()也必须拥有相同对象锁,否则也会抛出IllegalMonitorStateException异常static void yield() //该方法用于使当前线程主动让出当次CPU时间片回到Runnable状态,等待分配时间片。void join() //该方法用于等待当前线程结束,是一个阻塞方法。
线程的状态
- 新建状态(new):当线程对象创建后,即进入了新建状态,如:Thread t = new MyThread();
- 就绪状态(Runnable):当调用线程对象的start()方法线程即进入就绪状态。处于就绪状态的线程,只是说明此线程已经做好了等待CPU调度分配时间片的准备,并不是说执行了start()方法此线程就立即会执行。
- 运行状态(Running):当CPU开始调度处于就绪状态的线程时,此线程才开始真正执行,即进入到运行状态。
阻塞状态(Blocked):处于运行状态中的线程由于某种原因,暂时放弃对CPU的使用权,停止执行,此时进入阻塞状态,直到其进入就绪状态才有机会再次被CPU调用。阻塞状态可分为三种:
1.等待阻塞:运行状态中的线程执行wait()方法,使本线程进入到等待阻塞状态
2.同步阻塞:线程在获取synchronized同步锁(锁被其他线程所占用),它会进入同步阻塞状态
3.其他阻塞:通过调用线程的sleep()或join()或发出了IO请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、后者IO处理完毕时,线程重新转入就绪状态。- 死亡状态(Dead):线程执行完了或者因为异常退出了run()方法,该线程结束生命周期
停止线程
- 自然终止:线程体正常执行完毕
- 外部干涉
1.线程类中定义线程体使用的标识
2.线程体使用该标识
3.提供对外的方法改变该标识
4.外部根据条件调用该方法
public class Demo { public static void main(String[] args) { Study s = new Study(); new Thread(s).start(); for(int i=0; i<100; i++){ if(i == 50){ s.stop(); } System.out.println("main...."+i); } }}class Study implements Runnable{ private boolean flag = true; @Override public void run(){ while(flag){ System.out.println("study thread..."); } } public void stop(){ this.flag = false; }}
如果线程是阻塞的,则不能使用上面的方法来终止线程
public class ThreadInterrupt extends Thread { public void run() { try { sleep(50000); // 延迟50秒 } catch (InterruptedException e) { System.out.println(e.getMessage()); } } public static void main(String[] args) throws Exception { Thread thread = new ThreadInterrupt(); thread.start(); System.out.println("在50秒之内按任意键中断线程!"); System.in.read(); thread.interrupt(); thread.join(); System.out.println("线程已经退出!"); }}
线程阻塞
join
public class Demo extends Thread{ public static void main(String[] args) { Demo demo = new Demo(); Thread t = new Thread(demo); t.start(); for(int i=0;i<1000;i++){ if(i == 50){ try { t.join(); //main阻塞 } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("main............."+i); } } @Override public void run() { for(int i=0;i<100;i++){ System.out.println("join....."+i); } }}
当main执行到49的时候开始阻塞了,执行join。
yield
public class Demo extends Thread { public static void main(String[] args) { Demo demo = new Demo(); Thread t = new Thread(demo); t.start(); for(int i=0;i<1000;i++){ if(i % 20 ==0){ Thread.yield(); //暂停本线程 } System.out.println("main............."+i); } } @Override public void run() { for(int i=0;i<100;i++){ System.out.println("join....."+i); } }}
sleep
休眠,不释放锁。常用于
- 与时间相关:倒计时
- 模拟网络延时
倒计时
import java.text.SimpleDateFormat;import java.util.Date;/* * 倒计时 * 倒数10个数,一秒内打印一个 */public class Demo extends Thread { public static void main(String[] args) throws InterruptedException { Date endTime = new Date(System.currentTimeMillis()+10*1000); System.out.println(endTime); long end = endTime.getTime(); while(true){ //输出 System.out.println(new SimpleDateFormat("mm:ss").format(endTime)); //等待一秒 Thread.sleep(1000); //构建下一秒的时间 endTime = new Date(endTime.getTime()-1000); //10秒内继续,否则退出 if((end-10000)>endTime.getTime()){ break; } } }}
- Java多线程(二)认识Java里面的Thread
- Java多线程--认识多线程(Thread、Runnable)
- JAVA多线程变量的深入认识(二)
- Java多线程二:Thread类
- java多线程的认识
- Java多线程学习 (二) Thread的join()方法
- Java多线程(二) Thread和Runnable的基本用法
- 从头认识java-18.4 java多线程原子性操作里面的坑
- java多线程 基础(二) Thread Runnable
- Java多线程二:Thread类介绍
- java多线程里面的join
- Java多线程的初步认识
- 多线程二,Java多线程thread和runnable区别简介
- 【JAVA多线程】认识java多线程
- Thread多线程学习(二),java多线程中synchronize锁的使用和学习
- 【Java多线程】之二:Java Thread Sleep Example
- java Thread 多线程
- Java Thread 多线程 介绍
- 中国剩余定理+扩展
- py学习之路 第一是
- MySQL_explain关键字分析查询语句
- 产品框架3C方法论
- 【typical】【JZOJ 5296】Sequence
- Java多线程(二)认识Java里面的Thread
- PAT 1031 查验身份证
- 我们为什么要做一名系统管理员?
- C语言入门第七篇,强制类型转换和ASCll编码
- Redis使用简明教程
- poj 3007
- 二叉树:已知前序&&中序或中序&&后序构造树
- Codeforces Round #387 (Div. 2) A. Display Size
- HDU 2544 最短路