线程
相关概念
1.什么是进程?
进程是指一种正在运行的程序,有自己的地址空间。
2.什么是线程?
是进程的一个执行单元
3.什么是同步?
发送一个请求,需要等待回复,才能发送下一个请求。
4.什么是异步?
发送一个请求,不需要等待回复,可直接发送下一个请求
状态
1.新生态
在创建线程对象以后,还没有调用start方法之前()
2.可运行态
调用了start方法之后,线程的状态可能是正在运行的状态,也可能是处于等待运行的状态
3.阻塞态
一种“不可运行”的状态,在得到一个特定的事件之后会返回到可运行状态
4.死亡态
线程的run方法运行完毕或者在运行中出现未捕获的异常时
如何实现多线程
1.继承Thread类
(1)重写run方法(2)启动线程,调用start()
2.实现Runnable接口
重写run方法,Runnable中没有start方法 所以要依靠Thread类start()来启动线程,Thread类中可以封装Runnable对象
3.两种实现方式的区别?
- 继承Thread类 则不能再继承其他类,实现Runnable接口 则还可以继承其他的类
- 实现Runnable可以共享资源
注意:如果需要在Thread类使用时那么可以使用static关键字进行资源共享
线程常用的方法
1.isAlive 用于判定线程对象是否处于活动的状态
2.join —等待该线程终止。
//主线程开始
System.out.println("---main开始");
Tell te = new Tell();
te.start();
//-----两条线程同时运行
for (int i = 0; i < 30; i++) {System.out.println(Thread.currentThread().getName()+"*****"+i);
if(i == 10){
try {
te.join();//等待te终止 -----1.te线程执行完 再终止 2.te没有执行完就终止了
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
//主线程结束
System.out.println("---main结束");
}
3.sleep(毫秒数) ----休眠// run方法的开始
System.out.println("执行run方法");
try {
System.out.println(Thread.currentThread().getName());
Thread.sleep(5000);
System.out.println("线程完成休眠");
System.out.println(Thread.currentThread().getName());
System.out.println(Thread.currentThread().isAlive());
} catch (Exception e) {
System.out.println("休眠被打断");
return; // 返回到程序的调用处
}
System.out.println("线程正常终止");
让线程死亡的三种方法
让线程死亡的三种方法(都可以让线程死亡,但是这三种方式都比较暴力,导致线程还没有执行结束 就要死亡)
1.interrupt-----中断----“浇了一盆冷水”
2.destory-------“杀了”
3.stop------“一棒子敲死”
线程同步
1.wait():使一个线程处于等待状态,当线程执行wait()时,会把当前的锁释放,然后让出CPU,进入等待状态。
2.sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要捕捉InterruptedException异常,整个方法在调用的过程中,会出现阻塞状态,对持有资源一直保持持有状态。
3.notify():唤醒一个处于等待状态的线程,注意的是在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由JVM确定唤醒哪个线程,而且不是按优先级。(唤醒在此对象监视器上等待的单个线程。如果所有线程都在此对象上等待,则会选择唤醒其中一个线程。选择是任意性的,并在对实现做出决定时发生。线程通过调用其中一个 wait 方法,在对象的监视器上等待)
此方法只应由作为此对象监视器的所有者的线程来调用,(1)、通过执行此对象的同步 (Sychronized) 实例方法。( 2)、通过执行在此对象上进行同步的 synchronized 语句的正文。 (3)、对于 Class 类型的对象,可以通过执行该类的同步静态方法。
4.Allnotity():唤醒所有处入等待状态的线程,注意并不是给所有唤醒线程一个对象的锁,而是让它们竞争。
产生死锁的原因
过多的同步则会导致死锁
1、每条都占用自己的资源 如果其他线程来抢占资源时
2、当线程还没有执行结束----(线程还没有放开自己的运行资源时)如果其他线程此时要使用该资源时 则会导致死锁
3、强制抢占 ----线程在执行的时候,抢占同一资源时会发生死锁
4、当多条线程 分配资源变成一种首位相接的模式 ----也会导致死锁
守护线程
1,什么是守护线程?
守护进程(Daemon)是运行在后台的一种特殊进程。它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。使用isDaemon() 来判定线程是否是守护线程。
//让该条线程变成守护线程
te.setDaemon(true);
te.start();
2.yield ----暂停当前正在执行的线程对象,并执行其他线程。
作用:线程的礼让
线程池
1、什么是线程池?
线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。一般线程池里的线程都是用于后台处理,每个线程都使用默认的堆栈大小,以默认的优先级来运行,并且处于多线程的单元当中。
2.线程池的作用
当某个线程在托管代码中属于空闲的状态。可以将线程池插入 使CPU保持一个繁忙的状态,如果线程池中的线程都保持繁忙的状态 ,队列包含挂起的工作, 线程池将在一段时候后,创建一个辅助线程,线程的数目不会超过最大值。
3. 为什么要使用线程池
(1).减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务。
(2).可以根据系统的承受能力,调整线程池中工作线程的数目,为了防止消耗更多的内存,Java当中每条线程大约需要1MB的内存,消耗过多的内存,很容易导致死机。
4.Executors创建线程池
(1).newFixedThreadPool(int nThreads)----创建固定大小的线程池
(2).newSingleThreadExecutor() —创建只有一个线程的线程池
(3).newCachedThreadPool()—创建一个不限线程数上限的线程池,任何提交的任务都将立即执行