线程的基础知识
进程与线程:
进程是操作系统结构的基础,是程序 在一个数据集合上运行的过程,是系统进行资源分配和调度的基本单位。进程可以被看作程序的实体,同 样,它也是线程的容器。Windows任务管 理器,里面列表中的exe程序就是一个进程。进程它里面运行了很多子任务,这些 子任务有的加载网页,有的处理缓存,有的进行下载,这些子任务就是线程,是操作系统调度的最小单 元,也叫作轻量级进程。在一个进程中可以创建多个线程,这些线程都拥有各自的计数器、堆栈和局部变 量等属性,并且能够访问共享的内存变量。
多线程:
• 使用多线程可以减少程序的响应时间。如果某个操作很耗时,或者陷入长时间的等待,此时程序将不 会响应鼠标和键盘等的操作,使用多线程后可以把这个耗时的线程分配到一个单独的线程中去执行,从而 使程序具备了更好的交互性。
• 与进程相比,线程创建和切换开销更小,同时多线程在数据共享方面效率非常高。
• 多CPU或者多核计算机本身就具备执行多线程的能力。如果使用单个进程,将无法重复利用计算机资 源,这会造成资源的巨大浪费。在多CPU计算机中使用多线程能提高CPU的利用率。
• 使用多线程能简化程序的结构,使程序便于理解和维护
线程的状态:
Java线程在运行的声明周期中可能会处于6种不同的状态:
• New:新创建状态。线程被创建,还没有调用 start 方法,在线程运行之前还有一些基础工作要做。
• Runnable:可运行状态。一旦调用start方法,线程就处于Runnable状态。一个可运行的线程可能正在 运行也可能没有运行,这取决于操作系统给线程提供运行的时间。
• Blocked:阻塞状态。表示线程被锁阻塞,它暂时不活动。
• Waiting:等待状态。线程暂时不活动,并且不运行任何代码,这消耗最少的资源,直到线程调度器 重新激活它。
• Timed waiting:超时等待状态。和等待状态不同的是,它是可以在指定的时间自行返回的。
• Terminated:终止状态。表示当前线程已经执行完毕。导致线程终止有两种情况:第一种就是run方 法执行完毕正常退出;第二种就是因为一个没有捕获的异常而终止了run方法,导致线程进入终止状态。
线程状态的改变大致流程:线程创建后,调用 Thread 的 start 方法,开始进入运行状态,当线程执行wait 方法后, 线程进入等待状态,进入等待状态的线程需要其他线程通知才能返回运行状态。超时等待相当于在等待状 态加上了时间限制,如果超过时间限制,则线程返回运行状态。当线程调用到同步方法时,如果线程没有 获得锁则进入阻塞状态,当阻塞状态的线程获取到锁时则重新回到运行状态。当线程执行完毕或者遇到意 外异常终止时,都会进入终止状态。
创建线程的3种方式:
1.继承Thread类,重写run()方法 Thread本质上也是实现了Runnable接口的一个实例。需要注意的是调用start()方法后并不是立即地执 行多线程的代码,而是使该线程变为可运行态,什么时候运行多线程代码是由操作系统决定的。
public class TestThread extends Thread{public void run(){System.out.println("Hello world");}public static void main(){Thread mThread=new TestThread();mThread.start();}
}
2.实现Runnable接口,并实现该接口的run()方法
public class TestRunnable implements Runnable{public void run(){System.out.println("Hello world!"); }
}public class TestRunnable{public static void main(String[] args){TestRunnable mTestRunnable=new TestRunnable();Thread mThread=new Thread(mTestRunnable);mThread.start(); }
}
3.Callable接口实际是属于Executor框架中的功能类,Callable接口与Runnable接口的功能类似,但提供了 比Runnable更强大的功能,主要表现为以下3点:
(1)Callable可以在任务接受后提供一个返回值,Runnable无法提供这个功能。
(2)Callable中的call()方法可以抛出异常,而Runnable的run()方法不能抛出异常。
(3)运行Callable可以拿到一个Future对象,Future对象表示异步计算的结果,它提供了检查计算是否 完成的方法。由于线程属于异步计算模型,因此无法从别的线程中得到函数的返回值,在这种情况下就可 以使用 Future 来监视目标线程调用 call()方法的情况。但调用 Future的get()方法以获取结果时,当前 线程就会阻塞,直到call()方法返回结果。
public class TestCallable{//创建线程类public static class MyTestCallable implements Callable{public String call() throws Exception{return "Hello world"; } }public static void main(String[] args){MyTestCallable mMyTestCallable=new MyTestCallable():ExecutorService mExecutorService=Exectors.newSingleThreadPool();Future mfuture=mExecutorService.submit(mMyTestCallable);try{//等待线程结束,并返回结果System.put.println(mfuture.get());}catch(Exception e){e.printStackTrace();}}
}
线程的中断:
当线程的run方法执行完毕,或者在方法中出现没有捕获的异常时,线程将终止。在Java早期版本中有 一个stop方法,其他线程可以调用它终止线程,但是这个方法现在已经被弃用了。interrupt 方法可以用来请 求中断线程。当一个线程调用 interrupt 方法时,线程的中断标识位将被置位(中断标识位为true),线程会 不时地检测这个中断标识位,以判断线程是否应该被中断。要想知道线程是否被置位,可以调用 Thread.currentThread().isInterrupted()。
还可以调用Thread.interrupted()来对中断标识位进行复位。但是如果一个线程被阻塞,就无法检测中 断状态。如果一个线程处于阻塞状态,线程在检查中断标识位时如果发现中断标识位为true,则会在阻塞方 法调用处抛出InterruptedException异常,并且在抛出异常前将线程的中断标识位复位,即重新设置为 false。 需要注意的是被中断的线程不一定会终止,中断线程是为了引起线程的注意,被中断的线程可以决定如何 去响应中断。如果是比较重要的线程则不会理会中断,而大部分情况则是线程会将中断作为一个终止的请 求。另外,不要在底层代码里捕获InterruptedException异常后不做处理。【即catch捕获后要处理它】
抛出InterruptedException异常后如何处理:2种方式:
(1)在catch子句中,调用Thread.currentThread.interrupt()来设置中断状态(因为抛出异常后中断标 识位会复位),让外界通过判断Thread.currentThread().isInterrupted()来决定是否终止线程还是继续下 去。
try{
....
}catch(InterruptedException e){Thread.currentThread().interrupted();
}
.....
(2)更好的做法就是,不使用try来捕获这样的异常,让方法直接抛出,这样调用者可以捕获这个异 常:
void Demo() throw InterruptedException{.....
}
安全的终止线程:
用中断来终止线程:
public class StopThread{public static void main(String[] args) throws InterruptedException{MoonRunner runnable=new MoonRunner():Thread thread=new Thread(runnable,"MoonThread");thread.start();TimeUnit.MILLISECONDS.sleep(10);thread.interrupt();}
}public static class MoonRunner implements Runnable{private long i;@Overridepublic void run(){while(!Thread.currentThread().isInterrupted()){i++;System.out.println("i="+i);} System.out.println("stop");}
}
上述代码中,处调用了sleep方法使得main线程睡眠10ms,这是为了留给MoonThread线程时间来感 知中断从而结束。除了中断,还可以采用boolean变量来控制是否需要停止线程:
public class StopThread{public static void main(String[] args) throws InterruptedException{MoonRunner runnable=new MoonRunner():Thread thread=new Thread(runnable,"MoonThread");thread.start();TimeUnit.MILLISECONDS.sleep(10);runnable.cancel();}
}public static class MoonRunner implements Runnable{private long i;private volatile boolean on=true;@Overridepublic void run(){while(on){i++;System.out.println("i="+i);} System.out.println("stop");}public void cancel(){on=false;}
}
sahng因为 涉及多个线程对这个变量的访问,所以当我们在设置volatile boolean on的时候,当有其他线程改变其值时, 所有的线程都会感知到它的变化。这两种方式输出的结果类似.
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
