首先说下多线程出现的原因:
为了解决负载均衡问题,充分利用CPU资源.为了提高CPU的使用率,采用多线程的方式去同时完成几件事情而不互相干扰.为了处理大量的IO操作时或处理的情况需要花费大量的时间等等,比如:读写文件,视频图像的采集,处理,显示,保存等
多线程的好处:
1.使用线程可以把占据时间长的程序中的任务放到后台去处理
2.用户界面更加吸引人,这样比如用户点击了一个按钮去触发某件事件的处理,可以弹出一个进度条来显示处理的进度
3.程序的运行效率可能会提高
4.在一些等待的任务实现上如用户输入,文件读取和网络收发数据等,线程就比较有用了.
多线程的缺点:
1.如果有大量的线程,会影响性能,因为操作系统需要在它们之间切换.
2.更多的线程需要更多的内存空间
3.线程中止需要考虑对程序运行的影响.
4.通常块模型数据是在多个线程间共享的,需要防止线程死锁情况的发生
线程和进程的关系:
线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。一个进程可以并发多个线程,每条线程并行执行不同的任务。线程与进程的区别在于,线程是轻量级的进程,它共享进程的资源,如内存空间和文件句柄等。
线程的实现方式:
1. 继承Thread类 重写run方法 创建Thread类的子类的对象 通过此对象调用start()执行线程 2. 实现Runnable接口 实现run方法 创建实现类对象 将对象作为参数传递到Thread类的构造器中创建Thread对象 调用start() 1和2的比较: 开发中优先选择实现Runnable接口的方式 原因: 实现的方式没有类的单继承的局限性 实现的方式更适合来处理多个线程有共享数据的情况 相同点: 两种方式都需要重写run(),将线程要执行的逻辑声明在run()中 3. 实现Callable接口 实现call方法,将此线程需要执行的操作声明在call()中 创建Callable接口实现类的对象 将FtuireTask的对象作为传递到FutureTask构造器中,创建FutureTask的对象 将FutureTask的对象作为参数传递到Thread类的构造器中,插件Thread对象,调用start() 获取Callable中call方法的返回值 实现Callable接口的方式创建线程的强大之处 call()可以有返回值 call()可以抛出异常,被外面的操作捕获,获取异常的信息 Callable是支持泛型的 4.从线程池中获取 1.以方式二或方式三创建好实现了Runnable接口的类或实现Callable的实现类 2.实现run或call方法 3.创建线程池 4.调用线程池的execute方法执行某个线程,参数是执行器实现Runnable或Callable接口的对象 线程池的好处: 1.提高相应的速度(减少了创建线程的时间) 2.降低了资源消耗(重复利用线程池中线程,不需要每次都创建) 3.便于线程管理
如何实现线程间的通信?
线程间的通信可以通过以下几种方式实现:
-
共享变量:线程可以共享同一个变量来进行通信。
-
消息传递:线程可以通过发送消息来进行通信。
-
等待/通知机制:线程可以通过等待和通知来进行通信。
什么是线程安全?如何保证线程安全?
线程安全是指在多线程环境下,线程之间的共享数据不会出现竞争或不一致的情况。要保证线程安全,可以采用以下几种方式:
-
使用同步机制,如
synchronized
关键字、Lock
接口等。 -
使用线程安全的类,如
AtomicInteger
、ConcurrentHashMap
等。 -
避免共享可变的状态,尽量使用不可变对象或线程本地变量。
Java 中的线程有以下几种状态:
-
新建(New):线程刚创建,但还没有开始执行。
-
就绪(Runnable):线程已经准备好,可以随时执行。
-
运行(Running):线程正在执行。
-
阻塞(Blocked):线程在等待某些事件发生,如等待输入输出操作完成。
-
死亡(Dead):线程已经执行完毕。