[toc]
线程与进程
1 线程:进程中负责程序执行的执行单元
线程本身依靠程序进行运行
线程是程序中的顺序控制流,只能使用分配给程序的资源和环境
2 进程:执行中的程序
一个进程至少包含一个线程
3 单线程:程序中只存在一个线程,实际上主方法就是一个主线程
4 多线程:在一个程序中运行多个任务
目的是更好地使用CPU资源
线程的实现
继承Thread类
public class Test {
public static void main(String[] args) {
System.out.println("主线程ID:"+Thread.currentThread().getId());
MyThread thread1 = new MyThread("thread1");
thread1.start();
MyThread thread2 = new MyThread("thread2");
thread2.run();
}
}
class MyThread extends Thread{
private String name;
public MyThread(String name){
this.name = name;
}
@Override
public void run() {
System.out.println("name:"+name+" 子线程ID:"+Thread.currentThread().getId());
}
}
实现Runnable接口
public class Test {
public static void main(String[] args) {
System.out.println("主线程ID:"+Thread.currentThread().getId());
MyRunnable runnable = new MyRunnable();
Thread thread = new Thread(runnable);
thread.start();
}
}
class MyRunnable implements Runnable{
public MyRunnable() {
}
@Override
public void run() {
System.out.println("子线程ID:"+Thread.currentThread().getId());
}
}
静态方法
1.currentThread()
public class Test2 {
public static void main(String[] args) {
System.out.println("主线程ID:"+Thread.currentThread().getId());
System.out.println("主线程名字:"+Thread.currentThread().getName());
}
}
2.sleep()
public class Test2 {
private int i = 10;
private Object object = new Object();
public static void main(String[] args) throws IOException {
Test2 test = new Test2();
MyThread thread1 = test.new MyThread();
MyThread thread2 = test.new MyThread();
thread1.start();
thread2.start();
}
class MyThread extends Thread{
@Override
public void run() {
synchronized (object) {
i++;
System.out.println(Thread.currentThread().getName()+"===> i:"+i);
try {
System.out.println("线程"+Thread.currentThread().getName()+"进入睡眠状态");
Thread.currentThread().sleep(5000);
} catch (InterruptedException e) {
// TODO: handle exception
}
System.out.println("线程"+Thread.currentThread().getName()+"睡眠结束");
i++;
System.out.println("i:"+i);
}
}
}
}
Thread-0===> i:11
线程Thread-0进入睡眠状态
//这里会等待3000毫秒
线程Thread-0睡眠结束
i:12
Thread-1===> i:13
线程Thread-1进入睡眠状态
//这里会等待3000毫秒
线程Thread-1睡眠结束
i:14
3.yield
- 调用yield方法会让当前线程交出CPU权限,让CPU去执行其他的线程
- 但是yield不能控制具体的交出CPU的时间,另外,yield方法只能让拥有相同优先级的线程有获取CPU执行时间的机会。
- 注意,调用yield方法并不会让线程进入阻塞状态,而是让线程重回就绪状态,它只需要等待重新获取CPU执行时间,这一点是和sleep方法不一样的。
public class MyThread extends Thread{
@Override
public void run() {
long beginTime=System.currentTimeMillis();
int count=0;
for (int i=0;i<50000000;i++){
count=count+(i+1);
//Thread.yield();
}
long endTime=System.currentTimeMillis();
System.out.println("用时:"+(endTime-beginTime)+" 毫秒!");
}
}
public class Run {
public static void main(String[] args) {
MyThread t= new MyThread();
t.start();
}
}
注释======>用时:23毫秒!
取消注释==>用时:4890 毫秒!
对象方法
start()
start()用来启动一个线程,当调用start方法后,系统才会开启一个新的线程来执行用户定义的子任务,在这个过程中,会为相应的线程分配需要的资源。
run()
run()方法是不需要用户来调用的,当通过start方法启动一个线程之后,当线程获得了CPU执行时间,便进入run方法体去执行具体的任务。注意,继承Thread类必须重写run方法,在run方法中定义具体要执行的任务。
getId()
public class Run{
public static void main(String[] args) {
Thread thread = Thread.currentThread();
System.out.println(thread.getName());
System.out.println(thread.getId());
}
}
main
1
isAlive()
方法isAlive()的作用是测试线程是否偶处于活动状态。什么是活动状态呢?活动状态就是线程已经启动且尚未终止。线程处于正在运行或准备开始运行的状态,就认为线程是“存活”的。
public class Test {
public static void main(String[] args) throws InterruptedException {
MyThread thread2 = new MyThread("_2");
System.out.println(thread2.isAlive());
thread2.start();
Thread.sleep(1000);
System.out.println(thread2.isAlive());
}
}
class MyThread extends Thread{
private String name;
public MyThread(String name){
this.name = name;
}
@Override
public void run() {
System.out.println(this.isAlive());
}
}
false
true
false
join()
在很多情况下,主线程创建并启动了线程,如果子线程中药进行大量耗时运算,主线程往往将早于子线程结束之前结束。这时,如果主线程想等待子线程执行完成之后再结束,比如子线程处理一个数据,主线程要取得这个数据中的值,就要用到join()方法了。方法join()的作用是等待线程对象销毁。
public class Thread4 extends Thread{
public Thread4(String name) {
super(name);
}
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(getName() + " " + i);
}
}
public static void main(String[] args) throws InterruptedException {
// 启动子进程
new Thread4("new thread").start();
for (int i = 0; i < 10; i++) {
if (i == 5) {
Thread4 th = new Thread4("joined thread");
th.start();
th.join();
}
System.out.println(Thread.currentThread().getName() + " " + i);
}
}
}
有join方法:
main 0
main 1
main 2
main 3
main 4
new thread 0
new thread 1
new thread 2
new thread 3
new thread 4
joined thread 0
joined thread 1
joined thread 2
joined thread 3
joined thread 4
main 5
main 6
main 7
main 8
main 9
没有join方法:
main 0
main 1
main 2
main 3
main 4
main 5
main 6
main 7
main 8
main 9
new thread 0
joined thread 0
joined thread 1
joined thread 2
joined thread 3
joined thread 4
new thread 1
new thread 2
new thread 3
new thread 4
getName和setName()
用来得到或者设置线程名称。
getPriority和setPriority()
用来获取和设置线程优先级。
setDaemon和isDaemon()
用来设置线程是否成为守护线程和判断线程是否是守护线程。
停止线程
停止线程是在多线程开发时很重要的技术点,掌握此技术可以对线程的停止进行有效的处理。
停止一个线程可以使用Thread.stop()方法,但最好不用它。该方法是不安全的,已被弃用。
在Java中有以下3种方法可以终止正在运行的线程:
- 使用退出标志,使线程正常退出,也就是当run方法完成后线程终止
- 使用stop方法强行终止线程,但是不推荐使用这个方法,因为stop和suspend及resume一样,都是作废过期的方法,使用他们可能产生不可预料的结果。
- 使用interrupt方法中断线程,但这个不会终止一个正在运行的线程,还需要加入一个判断才可以完成线程的停止。
暂停线程
interrupt()方法
线程的优先级
JDK中使用3个常量来预置定义优先级的值,代码如下:
public final static int MIN_PRIORITY = 1;
public final static int NORM_PRIORITY = 5;
public final static int MAX_PRIORITY = 10;
线程优先级特性:
- 继承性
比如A线程启动B线程,则B线程的优先级与A是一样的。 - 规则性
高优先级的线程总是大部分先执行完,但不代表高优先级线程全部先执行完。 - 随机性
优先级较高的线程不一定每一次都先执行完。
守护线程
在Java线程中有两种线程,一种是User Thread(用户线程),另一种是Daemon Thread(守护线程)。
Daemon的作用是为其他线程的运行提供服务,比如说GC线程。其实User Thread线程和Daemon Thread守护线程本质上来说去没啥区别的,唯一的区别之处就在虚拟机的离开:如果User Thread全部撤离,那么Daemon Thread也就没啥线程好服务的了,所以虚拟机也就退出了。
守护线程并非虚拟机内部可以提供,用户也可以自行的设定守护线程,方法:public final void setDaemon(boolean on) ;但是有几点需要注意:
- thread.setDaemon(true)必须在thread.start()之前设置,否则会跑出一个IllegalThreadStateException异常。你不能把正在运行的常规线程设置为守护线程。 (备注:这点与守护进程有着明显的区别,守护进程是创建后,让进程摆脱原会话的控制+让进程摆脱原进程组的控制+让进程摆脱原控制终端的控制;所以说寄托于虚拟机的语言机制跟系统级语言有着本质上面的区别)
- 在Daemon线程中产生的新线程也是Daemon的。 (这一点又是有着本质的区别了:守护进程fork()出来的子进程不再是守护进程,尽管它把父进程的进程相关信息复制过去了,但是子进程的进程的父进程不是init进程,所谓的守护进程本质上说就是“父进程挂掉,init收养,然后文件0,1,2都是/dev/null,当前目录到/”)
- 不是所有的应用都可以分配给Daemon线程来进行服务,比如读写操作或者计算逻辑。因为在Daemon Thread还没来的及进行操作时,虚拟机可能已经退出了。
同步与死锁
- 同步代码块
在代码块上加上”synchronized”关键字,则此代码块就称为同步代码块 - 同步代码块格式
synchronized(同步对象){
需要同步的代码块;
}
同步方法
除了代码块可以同步,方法也是可以同步的方法同步格式
synchronized void 方法名称(){}
参考:
http://www.importnew.com/21136.html