Java基础之多线程

线程中run()和start()的区别:
对于Thread对象来说,当你调用的是start(),线程会被放到等待队列,等待CPU调度,不一定马上执行;无需等待run()方法执行完毕,可以直接执行下面的代码;
而调用的是run()的话,就是当做普通的方法调用,程序还是要顺序执行的;
新建线程的几种方式:
实现Runnable接口;里面实现run()方法;
然后把这个实现了Runnable接口的类就新建为一个Thread t = new Thread(new (实现Runnable接口的类)),调用start()方法即可开始一个线程了。记住,start()只是开启,然后就会返回,继续执行start()下面的语句了。

线程执行器:
我们可以通过不同的线程执行器来实现多线程的执行,有以下几种执行器:

ExecutorService exec = Executors.newCachedThreadPool();

ExecutorService exec = Executors.newFixedThreadPool(5);

ExecutorService exec = Executors.newSingleThreadExecutor();

我们可以对比一下这三者的区别:第一个执行会为每一个任务都创建一个线程,
而第二个则是可以一次性指定要分配多少线程,而第三个则是属于单线程,会一个线程一个线程的依次执行;

休眠:
会使得任务中断一段时间,相当于变相的阻塞了,可以给其他线程制造机会去执行;
但是我们不能通过sleep()来试图控制线程的顺序执行,而是要考虑用同步控制来实现;

让步:
通过使用yield()方法来给线程调度机制一个暗示:你的工作已经完成的差不多了,可以让别的线程使用CPU了,其功能上跟sleep()其实是差不多的。

后台线程:
指在程序运行的时候在后台提供一种通用服务的线程,并且这种线程并不属于程序总共不可或缺的部分,当所有非后台线程结束时,程序终止;由后台线程创建的线程也是后台线程;
在线程调用start()之前,调用setDaemon(true);

实现多线程的另一种方式:
通过继承Thread的方式来实现:而且run()方法是放在构造函数里面的,也就是说,当初始化一个线程的时候,就自动的开启了线程,记得run()方法里面一般都是一个while()循环;

加入一个线程:
一个线程可以在其他线程之上调用join()方法,如果某个线程在另一个线程t上调用t.join();此线程将被挂起,知道目标线程t结束才恢复;
join()方法,你在一个线程中join()了一个线程进来,你就要等待这个线程结束了,才可以把自己这个线程给结束掉;join()的底层实现是wait()方法;

同步:
Synchronzied;可以用在方法上,也可以用到类上面;

显式地使用lock对象
先用Lock lock = new ReentrantLock();建出一个锁对象出来,然后在方法里面,先调用lock.lock();然后try语句里面是方法体,最后记得要在finally里面加上lock.unlock();这样就就相当于解锁了。

区别:
可以看到synchronized lock相比起来,lock似乎要加上一些try/catch语句才可以,但是,这也是好处之一,比起synchronized,可以多出来处理的过程,让用户出现错误的可能性降低;
使用原子类也可以实现资源共享的问题,但是原子类一般很少在常规编程中用到,用于性能调优,然后AtomicInteger,AtomicLong等原子类,使用这些的时候,不需要用到synchronized和lock,但是原子类很少用到,所以我们还是用synchronized和lock。

线程的状态:
新建;就绪;阻塞;死亡;

导致阻塞的几个原因:
1,通过调用sleep()使任务进入休眠状态,

2,通过调用wait()使线程挂起,知道线程得到notify()notifyAll()消息,

3,任务再等待某个输入/输出完成;

4,任务视图在某个对象上调用其同步控制方法,但是对象锁不可用,因为另一个任务已经获取了这个锁;

中断:
这是一个大学问呀。一般的话,我们中断都是用interrupted(),但是,我们现在说了,用Executor执行器可以更好地执行了,所以我们如如何在执行器中中断线程呢?这也很好办,用Executor的shutdownNow(),但是,这又是一个问题了,这只是用来中断所有的线程的,但是我们是想要中断某一个线层那该怎么办呢?这就用到了返回式了,通过submit()来启动任务的时候,我们就能够得到返回的类型Future<?>通过这个去调用calcel()来中断某个线程。具体等一下码,现在还要讨论的还有一个问题,中断的线程是否有一些是无法中断的,判定如下:如果是在sleep()中的线程,那么显然是可以中断的,但是对于正在读取I/O的线程和正在试图获取锁的线程,我们是无法中断的,而中断线程就相当于抛出了一个异常,方便我们关闭掉资源。

线程之间的协作:
当线程同时运行多个任务时,我们可以用锁来同步两个任务的行为,同时也可以用wait()notifyAll()来实现对线程的控制;
wait()就是一种挂起的状态,当你挂起了之后,锁将被释放,把空出来的线程,给别人执行,而等到被调用notify()唤醒之后,又会重新获得之前wait()锁,如果这个时候锁正在被使用的话,就要陷入等待了。

wait()跟sleep()之间的区别:
1,在synchronized中,wait()期间对象锁是释放的;而sleep()锁是不会释放的;

2,可以通过notify(),notifyAll(),或者令时间到期,从wait()中恢复执行;

唤醒的区别:
notify()方法保证的唤醒是指唤醒的是恰当的任务,另外,为了使用notify(),你必须等待相同的条件,而对于notifyAll()来说,是否所有的线程都会被唤醒呢?只有当notifyAll()因某个特定锁被调用时,只有等待这个锁的任务才能被唤醒;

除了wait()和notify(),我们还可以显式地使用lock和Condition对象;
使用互斥并允许任务挂起的基本类是Condition;可以通过在Condition上调用await来挂起一个任务,通过signal()来通知这个任务,唤醒这个任务,或者调用signalAll()来唤醒所有在这个Condition上被其自身挂起的任务;与使用notify()相比,signlAll()是更安全的方式;

Lock lock = new ReentrantLock();

Condition condition = lock.newCondition();

lock.lock();

lock.unlock();

condition.await();

但是我们要知道显式的lock对象,相比起wait(),notify()来说,更加复杂,所以还是建议用回原来的那个wait(),LockCondition只有在更加困难的多线程问题才是必需的;

死锁:
当某一个任务在等待另一个任务的锁释放,而下一个任务又在等待上一个锁的释放,在这样呈链式的循环里面,直到这个链条上的任务又在等待第一个任务释放锁,得到了一个任务之间的相互等待的连续循环;称为死锁;
哲学家就餐问题;经典的死锁问题;
发生死锁的四个满足条件:

1,互斥条件,任务使用的资源中国至少有一个是不能共享的。

2,至少有一个任务它必须持有一个资源把那个正在等待获取另一个被别的任务持有的资源;

3,资源不能被任务抢占;

4,必须要有等待循环;

防止死锁的最容易的方式是破坏第四个条件。

总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对我们的支持。如果你想了解更多相关内容请查看下面相关链接

(0)

相关推荐

  • 实例总结Java多线程编程的方法

    1.什么时候使用多线程编程 一个任务在正常情况下是按顺序执行的,但是如果当前任务里有多个相似进程块(例如for,while语句),我们就可以考虑把这些代码块抽出来并行运行,无需阻塞 2.实现多线程的几种方式 一种是继承Thread类重写run方法,另一种是实现Runnable接口重写run方法 启动多线程很多情况下是为了处理并发进程,此时对于部分实时性要求不是那么高的业务需求,我们还可以通过实现队列的方式,异步实现. 3.举例 继承Thread /** * * @ClassName: Threa

  • java多线程开发之通过对战游戏学习CyclicBarrier

    CyclicBarrier是java.util.concurrent包下面的一个工具类,字面意思是可循环使用(Cyclic)的屏障(Barrier),通过它可以实现让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,所有被屏障拦截的线程才会继续执行. 这篇文章将介绍CyclicBarrier这个同步工具类的以下几点 通过案例分析 两种不同构造函数测试 CyclicBarrier和CountDownLatch的区别 await方法及源码分析. 需求 继上一篇CountDo

  • Java多线程死锁示例

    本文实例演示了Java多线程死锁.分享给大家供大家参考,具体如下: package com.damlab.fz; public class DeadLock { public static void main(String[] args) { Resource r1 = new Resource(); Resource r2 = new Resource(); // 每个线程都拥有r1,r2两个对象 Thread myTh1 = new MyThread1(r1, r2); Thread myT

  • Java多线程通讯之wait,notify的区别详解

    下面通过代码给大家介绍java多线程通讯之wait notify的区别,具体内容如下所示: class Res{ public String username; public String sex; } class Out extends Thread{ Res res; public Out(Res res){ this.res=res; } @Override public void run() { //写操作 int count=0; while (true){ // synchroniz

  • java多线程Thread-per-Message模式详解

    Thread-per-Message模式(这项工作就交给你了) 当你很忙碌的时候,这个时候公司楼下有个快递,于是你委托你的同事帮你拿一下你的快递,这样你就可以继续做自己的工作了 在Thread-Per-Message模式中,消息的委托端和执行端是不同的线程,消息的委托端会告诉执行端线程,这个工作就交给你了 Host类: 针对请求创建线程的类,主要通过开启新的线程,调用helper的handle,并将要打印的文字传递. public class Host { private final Helpe

  • java模拟多线程http请求代码分享

    java模拟http发送请求,第一种是HttpURLConnection发送post请求,第二种是使用httpclient模拟post请求, 实例代码: package test; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.Exec

  • Java多线程之Callable接口的实现

    1.接口的定义: public interface Callable<V> { V call() throws Exception; } 2.Callable和Runnable的异同 先看下Runnable接口的定义 public interface Runnable { public abstract void run(); } Callable的call()方法类似于Runnable接口中run()方法,都定义任务要完成的工作,实现这两个接口时要分别重写这两个方法,主要的不同之处是call

  • Java使用Thread创建多线程并启动操作示例

    本文实例讲述了Java使用Thread创建多线程并启动操作.分享给大家供大家参考,具体如下: 按照教程实现了一个单线程的创建,但是单线程的创建于启动并不是很有实用价值的.毕竟直接在main方法中放着相关的执行操作本身也就是一种单线程的实现.接下来在之前用过的代码基础上稍作修改,形成如下代码: class ThreadDemo extends Thread { ThreadDemo(){}; ThreadDemo(String szName) { super(szName); } public v

  • Java基础之多线程的三种实现方式

    一.前言 Java多线程实现的三种方式有继承Thread类,实现Runnable接口,使用ExectorService.Callable.Future实现有返回结果的多线程.其中前两种方式线程执行完后都没有返回值,只有最后一种是带返回值的. 二.继承Thread类实现多线程 1.Thread本质上也是实现了Runnable接口的一个实例,它代表一个线程的实例,并且,启动线程的唯一方法就是通过Thread类的start()实例方法. 2.start()方法是一个native方法,它将启动一个新线程

  • Java基础之多线程方法状态和创建方法

    目录 Java之线程的五大状态及其常用方法(六个状态还有timed_wating超时等待) 1.线程的五大状态及其转换 2.设置或获取多线程的线程名称的方法 3.线程休眠------sleep()方法 4.线程让步------yield()方法 5. 等待线程终止------join()方法 6. 线程停止 7. 线程等待------wait()方法 8. 线程唤醒-------notify()方法 9. notifyAll()方法 JAVA多线程有哪几种实现方式? 1. 继承Thread类 2

  • Java基础之多线程

    线程中run()和start()的区别: 对于Thread对象来说,当你调用的是start(),线程会被放到等待队列,等待CPU调度,不一定马上执行:无需等待run()方法执行完毕,可以直接执行下面的代码: 而调用的是run()的话,就是当做普通的方法调用,程序还是要顺序执行的: 新建线程的几种方式: 实现Runnable接口:里面实现run()方法: 然后把这个实现了Runnable接口的类就新建为一个Thread t = new Thread(new (实现Runnable接口的类)),调用

  • java 基础教程之多线程详解及简单实例

    java 多线程详解 在这篇文章里,我们关注多线程.多线程是一个复杂的话题,包含了很多内容,这篇文章主要关注线程的基本属性.如何创建线程.线程的状态切换以及线程通信. 线程是操作系统运行的基本单位,它被封装在进程中,一个进程可以包含多个线程.即使我们不手动创造线程,进程也会有一个默认的线程在运行. 对于JVM来说,当我们编写一个单线程的程序去运行时,JVM中也是有至少两个线程在运行,一个是我们创建的程序,一个是垃圾回收. 线程基本信息 我们可以通过Thread.currentThread()方法

  • Java编程之多线程死锁与线程间通信简单实现代码

    死锁定义 死锁是指两个或者多个线程被永久阻塞的一种局面,产生的前提是要有两个或两个以上的线程,并且来操作两个或者多个以上的共同资源:我的理解是用两个线程来举例,现有线程A和B同时操作两个共同资源a和b,A操作a的时候上锁LockA,继续执行的时候,A还需要LockB进行下面的操作,这个时候b资源在被B线程操作,刚好被上了锁LockB,假如此时线程B刚好释放了LockB则没有问题,但没有释放LockB锁的时候,线程A和B形成了对LockB锁资源的争夺,从而造成阻塞,形成死锁:具体其死锁代码如下:

  • Java基础知识汇总

    Java基础知识 1.Java语言的优点: 1)Java是纯面向对象语言 2)与平台无关性,一次编译到处运行 3)Java提供了狠多内置类库 4)提供了对web应用的支持 5)具有较好的安全性(数组边界检测.Bytecode检测)和健壮性(强制型机制.垃圾回收器.异常处理) 6)去除c++难以理解的一些特性(头文件 指针 运算符重载 多重继承) 2.java与c++的异同: 1)Java为解释型语言,c++为编译型语言,java会慢但是跨平台 2)Jave为纯面向对象,c++既面向对象又能面向过

  • Java 基础之修饰符关键词整理

    Java 基础之修饰符关键词整理 我成为一个Java程序员距今已有一段时日.最近,有人问我关于Java修饰符关键字的一个问题,但我根本不知道那是什么.所以我觉得除了实际编程和算法,我也有必要学习这些内容. 通过谷歌搜索,我只得到一些琐碎的要点,并不完整.所以我以此主题写了这篇文章.这也是一个可用于测试你的计算机科学知识的面试问题. Java修饰符是你添加到变量.类和方法以改变其含义的关键词.它们可分为两组: 访问控制修饰符 非访问修饰符 让我们先来看看访问控制修饰符,以及如何使用它们的一些代码示

  • java 基础知识之网络通信(TCP通信、UDP通信、多播以及NIO)总结

    java 基础知识之网路通信总结 在这篇文章里,我们主要讨论如何使用Java实现网络通信,包括TCP通信.UDP通信.多播以及NIO. TCP连接 TCP的基础是Socket,在TCP连接中,我们会使用ServerSocket和Socket,当客户端和服务器建立连接以后,剩下的基本就是对I/O的控制了. 我们先来看一个简单的TCP通信,它分为客户端和服务器端. 客户端代码如下: 简单的TCP客户端 import java.net.*; import java.io.*; public class

  • Java基础之代码死循环详解

    一.前言 代码死循环这个话题,个人觉得还是挺有趣的.因为只要是开发人员,必定会踩过这个坑.如果真的没踩过,只能说明你代码写少了,或者是真正的大神. 尽管很多时候,我们在极力避免这类问题的发生,但很多时候,死循环却悄咪咪的来了,坑你于无形之中.我敢保证,如果你读完这篇文章,一定会对代码死循环有一些新的认识,学到一些非常实用的经验,少走一些弯路. 二.死循环的危害 我们先来一起了解一下,代码死循环到底有哪些危害? 程序进入假死状态, 当某个请求导致的死循环,该请求将会在很大的一段时间内,都无法获取接

  • Java基础之垃圾回收机制详解

    一.GC的作用 进行内存管理 C语言中的内存,申请内存之后需要手动释放:一旦忘记释放,就会发生内存泄漏! 而Java语言中,申请内存后会由GC来释放内存空间,无需手动释放 GC虽然代替了手动释放的操作,但是它也有局限性: 需要消耗更多的资源: 没有手动释放那么及时: STW(Stop The World)会影响程序的执行效率 二.GC主要回收哪些内存 (1)堆:主要回收堆中的内存 (2)方法区:需要回收 (3)栈(包括本地方法栈和JVM虚拟机栈):不需要回收,栈上的内存什么时候释放是明确的(线程

随机推荐