Java并发编程(一)——线程
2016-03-21 11:41
253 查看
Java并发编程(一)——线程
一,线程的实现方式
Java中实现多线程有两种方式,如下:1,继承java.lang.Thread类,重写run()方法; 2,实现java.lang.Runnable接口,重写接口中的run()方法。
这两种实现方式没有优劣,但由于Java中不允许多继承,所以使用第二种实现接口的方式更加灵活。
另外需要注意的是实现了Runnable的类,就像其字面描述的意思一样,只是一个可运行的东西,最终也是要Thread类来启动它,它才能跑起来。这一点从源码上分析来看,只能说Runnable接口只是为了用来在不能多继承的情况下来实现多线程而设计的,最终线程的内容和启动还是Thread来实现的。
代码如下:
public class ThreadDemo { public static void main(String[] args) { Thread t = new Thread(); t.start(); Thread t2 = new Thread(new Line()); t2.start(); } } class Line implements Runnable{ @Override public void run() { System.out.println("Line Thread is running..."); } }
而更多的情况下,我们会采用匿名内部类来实现多线程:
public static void main(String[] args) { new Thread(new Runnable() { @Override public void run() { System.out.println("I'm a new Thread"); } }).start(); }
二,线程的生命周期
线程的生命周期是指一个线程从创建到消亡的过程。新建状态(New)
当用new操作符创建一个新的线程对象时,该线程处于创建状态。处于创建状态的线程只是一个空的线程对象,系统不为它分配资源。
注意:不能对已经启动的线程再次调用start()方法,否则会出现java.lang.IllegalThreadStateException异常。如下:
Thread t = new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("I'm a new Thread"); } }); t.start(); t.start();//同一个(同id)线程不能同时启动两次
另,线程是不能clone的,因为线程id是不能重复的,会抛出CloneNotSupportedException异常,见源码:
@Override protected Object clone() throws CloneNotSupportedException { throw new CloneNotSupportedException(); }
就绪状态(Runnable)
线程对象创建后,其他线程调用了该对象的start()方法。该状态的线程位于可运行线程池中,变得可运行,等待获取CPU的使用权。
运行状态(Running)
就绪状态的线程获取了CPU的使用权,执行程序代码的过程就处于运行态。
阻塞状态(Blocked)
阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的情况分三种:
(1)等待阻塞:运行的线程执行wait()方法,JVM会把该线程放入等待池中。
(2)同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池中。
(3)其他阻塞:运行的线程执行sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
死亡状态(Dead)
线程执行完了或者因异常退出了run()方法,该线程结束生命周期。
三,线程状态的转换
1,线程生命周期图2,线程状态的切换方式:
1)yield():yield的意思是让步,让出,就是暂时让出CPU的使用权,所以从Running变为了Runnable状态。
2)sleep():使线程睡眠一定的时间,由Running态变为Blocked态。
3)join():使当前线程(如主线程)挂起,直到调用join方法的线程执行完毕。
4)exit():在线程进入Running之前可以清空并退出该线程。
5)stop():强制线程退出,
已废弃。
6)suspend():挂起线程,由Running变为Blocked,和resume相对应,
已废弃。
7)resume():恢复线程,由Blocked变为Runnable,
已废弃。
8)interrupt():打断/中断线程。
四,Thread类的常用API
void setName(String name):为线程设置线程名;
守护线程和用户线程的区别在于:守护线程依赖于创建它的线程,而用户线程则不依赖。举个简单的例子:如果在main线程中创建了一个守护线程,当main方法运行完毕之后,守护线程也会随着消亡。而用户线程则不会,用户线程会一直运行直到其运行完毕。在JVM中,像垃圾收集器线程就是守护线程。
void setDaemon(boolean on):设置是否是守护线程,是谁的守护线程?是当前线程的守护线程;需要在start方法调用之前使用;另,在Daemon线程中产生或新建的新线程默认也是Daemon的。
public class DaemonDemo { public static void main(String[] args) throws InterruptedException { TestThread test = new TestThread(); // 如果不设置daemon,那么线程将输出10后才结束 test.setDaemon(true); test.start(); System.out.println("isDaemon = " + test.isDaemon()); try { System.in.read(); // 接受输入,使程序在此停顿,一旦接收到用户输入,main线程结束,守护线程自动结束 } catch (IOException ex) { ex.printStackTrace(); } } } class TestThread extends Thread { public void run() { for (int i = 1;; i++) { try { Thread.sleep(1000); } catch (InterruptedException ex) { ex.printStackTrace(); } System.out.println(i); } } }
boolean isDaemon():判断是否是守护线程;
void setPriority(int newPriority):设置线程优先级,默认为5,最小为1,最大为10;优先级越高,越能更早的获取CPU调度;
Thread currentThread():返回当前线程对象的一个引用,为什么不用this?见下篇博客
int activeCount():返回当前线程所在的线程组中活跃线程的数量;
相关文章推荐
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Android IPC进程间通讯机制
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- Python3写爬虫(四)多线程实现数据爬取
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- PropertyChangeListener简单理解
- c++11 + SDL2 + ffmpeg +OpenAL + java = Android播放器
- 插入排序
- 冒泡排序
- 堆排序
- 快速排序