java语言里的线程本质上就是操做系统的线程,他们是一 一对应的java
Java语言中线程共有六种状态,分别是:算法
BLOCKED,WAITING,TIMED_WAITING 是上面提到的休眠状态。Java线程处于这些状态那么这个线程就永远没有CPU的使用权。编程
线程能够经过isInterrupted()方法,检 测是否是本身被中断了。安全
Java刚建立出来的Thread对象就是NEW状态,而建立Thread对象主要有两种方法。一种是继承Thread对 象,重写run()方法。示例代码以下:多线程
方式一: 继承Thread并发
// ⾃定义线程对象 class MyThread extends Thread{ public void run() { // 线程须要执⾏的代码 } } // 建立线程对象 MyThread myThread = new MyThread();
方式二: 实现Runnable接口异步
//实现Runnable接⼝ class Runner implements Runnable { @Override public void run(){ //线程须要执⾏的代码 } } //建立线程对象 Thread thread = new Thread(new Runner());
方式三:实现Callable接口编程语言
//实现Runnable接⼝ class Runner implements Callable<String> { @Override public String call() throws Exception { //线程须要执⾏的代码 return null; } } //建立 FutureTask FutureTask<String> ft1 = new FutureTask(new Runner()); //执行这个任务 Thread t1 = new Thread(ft1); t1.start(); //获取返回值 t1.get();
方法三实质上也是实现了Runnable接口,由于FutureTask实现了Runnable接口ide
Future接口提供的方法:性能
// 取消任务 boolean cancel(boolean mayInterruptIfRunning); // 判断任务是否已取消 boolean isCancelled(); // 判断任务是否已结束 boolean isDone(); // 得到任务执⾏结果 get(); // 得到任务执⾏结果,⽀持超时 get(long timeout, TimeUnit unit);
这两个get()方法都是阻塞式的,若是被调用的时候,任务尚未执行完,那么调用get()方法的线程会阻塞,直到任务执行完才会被唤醒。
stop()会杀死线程,若是线程持有ReentrantLock锁,被stop()的线程并不会自动调用ReentrantLock的unlock()去释放锁,那其余线程就再也没机会得到ReentrantLock锁。因此该方法就不建议使用了,相似的方法还有suspend()和resume()方法,这两个方法一样也都不建议使用。
interrupt()仅仅是通知线程,线程有机会执行一些后续操做,同时也能够无视这个通知。
提升程序的性能: 下降延迟,提升吞吐量。
提升性能的方式:1优化算法;2将硬件的性能发挥到极致
在并发编程领域,提高性能本质上就是提高硬件的利用率,具体来讲就是提高I/O的利用率和CPU的利用率。
若是CPU和I/O设备的利用率都很低,那么能够尝试经过增长线程提升吞吐量。
咱们的成语通常都是CPU计算和I/O操做交叉执行的,因为I/O设备的速度相对于CPU来讲都是很慢的,因此大部分状况下,I/O操做的执行时间相对于CPU计算来讲都很是长,这种场景咱们通常都成为I/O密集型程序和CPU密集型程序,计算最近线程数的方法是不一样的。
对于CPU密集型的计算场景,理论上“线程的数量-CPU核数”就是最合适的。不过在工程上,线程的数量通常会设置为"CPU核数+1" ,这样的话,当线程由于偶尔的内存页失效或其余缘由致使阻塞时,这个额外的线程能够顶上,从而保证CPU的利用率。
对于I/O密集型的计算场景,好比前面咱们的例子中,若是CPU计算和I/O操做的耗时是1:1,那么2个线程是 最合适的。若是CPU计算和I/O操做的耗时是1:2,那多少个线程合适呢?是3个线程,以下图所示:CPU在 A、B、C三个线程之间切换,对于线程A,当CPU从B、C切换回来时,线程A正好执行完I/O操做。这样CPU 和I/O设备的利用率都达到了100%。
更多的精力其实应该放在算法的优化上,线程池的配置,按照经验配置一个,随时关注线程池大小对程序 的影响便可,具体作法:能够为你的程序配置一个全局的线程池,须要异步执行的任务,扔到这个全局线 程池处理,线程池大小按照经验设置,每隔一段时间打印一下线程池的利用率,作到内心有数。
设置线程数的原则: 将硬件的性能发挥到极致。
每一个线程都有本身的调用栈,局部变量保存在线程各自的调用栈里面,不会共享,因此天然也就没有并发问题。
局部变量的做用域是方法内部,也就是说当方法执行完,局部变量就没用了,局部变量和方法同生共死。
局部变量是和方法同生共死的,一个变量若是想跨越方法的边界,就必须建立在堆里。
两个线程能够同时用不一样的参数调用相同的方法。
每一个线程都有本身独立的调用栈。
线程封闭 : 仅在单线程内访问数据。不存在多线程的数据共享。
由于每调用一个方法就会在栈上建立一个栈帧,方法调用结束后就会弹出该栈帧,而栈的大小不是无限的 ,因此递归调用次数过多的话就会致使栈溢出。而递归调用的特色是每递归一次,就要建立一个新的栈帧 ,并且还要保留以前的环境(栈帧),直到遇到结束条件。因此递归调用必定要明确好结束条件,不要出现死循环,并且要避免栈太深。
解决方法:
**** 码字不易若是对你有帮助请给个关注****
**** 爱技术爱生活 QQ群: 894109590****