线程状态
当线程被创建并启动以后,它既不是一启动就进入了执行状态,也不是一直处于执行状态。在线程的生命周期中,在API中,java.lang.Thread.State这个枚举中给出了六种线程状态:
1.NEW(新建) 线程刚被创建,但是并未启动,还没调用start方法
2。Runnable(可运行) 线程可以在java虚拟机中运行的状态,可能正在运行自己代码,也可能没有,这取决于操作系统处理器。
3.Blocked(锁阻塞) 当一个线程试图获取一个对象锁,而该对象锁被其他的线程持有,则该线程进入Blocked状态;当该线程持有锁时,该线程将变成Runnable状态
4.Waiting(无限等待) 一个线程在等待另一个线程执行一个(唤醒)动作时,该线程进入Waiting状态,进入这个状态后是不能自动唤醒的,必须等待另一个线程调用notify或者notifyAll方法才能够唤醒
5.Timed Waiting(计时等待) 同waiting状态,有几个方法有超时参数,调用他们将进入Timed Waiting状态。这一状态将一直保持到超时期满或者接受到唤醒通知。带有超时参数的常用方法有Thread.sleep、Object.wait
6.Teminated(被终止) 因为run方法正常退出而死亡,或者因为没有捕获的异常终止了run方法而死亡。
无限等待_wait方法
public class Demo{
public static void main(String[] args) throws InterruptedException
Object obj=new Object();
new Thread(){
@Override
synchronized(obj){
for(int i=0;i<20;i++){
System.out.println("i=" +i);
try{
Thread.sleep(1000);
}catch(InterruptedException e){
e.printStackTrace();
}
if(i==10){
try{
System.out.println("我开始等待..")
obj.wait();
System.out.println("我醒了,开始执行下面的...")
}catch(InterruptedException e){
e.printStackTrace();
}
}
}
}.start();
new Thread(){
@Override
public vodi run(){
System.out.println("第二个线程开始执行..");
synchronized(obj){
System.out.println("第二个线程开始唤醒...");
obj.notifyAll();
}
}.start();
}
}
}
经典案例包子铺卖包子
包子铺线程
public class BaoZiPu extends Thread {
private List<String> list;
public BaoZiPu(List<String> list){
this.list=list;
}
@Override
public void run(){
int index=1;
while(true){
synchronized(list){
try{
Thread.sleep(1000);
}catch(InterruptedException e){
e.printStackTrace();
}
System.out.println("做一个包子"+index);
list.add("包子"+index++);
list.notifyAll();
}
}
}
}
吃货线程
public class ChiHuo extends Thread{
private List<String> list;
public ChiHuo(List<String> list){
this.list=list;
}
@Override
public void run(){
while(true){
synchronized(list){
try{
Thread.sleep(1000);
}catch(InterruptedException e){
e.printStackTrace();
}
if(list.size==0){
try{
list.wait();
}catch(InterruptedException e){
e.printStackTrace();
}
}
System.out.println("取走"+list。remove(0));
list.notifyAll();
}
}
}
}
测试类
public class Test{
public static void main(String[] args){
List<String> list=new ArrayList<>();
BaoZiPu b=new BaoZiPu(list);
ChiHuo c=new ChiHuo(list);
b.start();
a.start();
}
}
线程池
线程池指封装了很多的“线程对象”的一个容器。这样,线程池内部的这些线程对象可以被重复使用。
线程对象每次使用完成后,会自动成为垃圾,不能再次的start,如果想要再次使用就需要再次创建,但创建一个线程对象需要很大的系统开销,所以如果需要大量的、反复的执行同一线程会降低程序的效率。所以提出了“线程池”的概念。
继承Thread和实现Runnable接口都是重写run()方法,不能返回值。
例子:
线程:
public class MyRunnable implements Runnable{
@Override
public void run() {
System.out.println("我想要一个教练");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("教练来了"+Thread.currentThread().getName());
System.out.println("教我游泳,教完后,教练回到了游泳池");
}
}
测试
public class test {
public static void main(String[] args) {
ExecutorService service= Executors.newFixedThreadPool(3);//创建了3个线程对象
MyRunnable r=new MyRunnable();
service.submit(r);
service.submit(r);
service.submit(r);
service.shutdown();
}
}
从JDK5开始,又提供了实现线程的第三种方式:实现Callable接口,重写call()方法,这个方法可以返回值
Callable接口的方式实现线程,需要线程池来运行
例如:
线程:
public class MyCallable implements Callable<Integer> {
@Override
public Integer call() throws Exception {
int sum=0;
for (int i = 0; i <= 100 ; i++) {
sum+=i;
}
return sum;
}
}
实现类
public class Test1 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService service = Executors.newFixedThreadPool(2);
MyCallable myCall = new MyCallable();
Future<Integer> future=service.submit(myCall);
Integer result = future.get();
System.out.println("主线程收到的结果是:"+result);
service.shutdown();
}
}