java 多线程并发 应用_java多线程并发(一)

并发编程会面临什么样的问题?

并发编程会面临非常多的挑战,比如:上下文切换问题、死锁问题、以及受限于硬件和软件的资源限制问题。

2.1 什么是上下文切换?

CPU通过时间片分配算法来循环执行任务,当前任务执行一个时间片后会切换到下一个任务。但是,在切换前会保存上一个任务的状态,以便下次切换回这个任务时,可以再加载这个任务的状态。所以任务从保存到再加载的过程就是一次上下文切换。

上下文切换会带来什么样的影响?

上下文的切换会影响多线程的执行速度

如何减少上下文切换?

减少上下文切换的方法:无锁并发编程、CAS算法、使用最少线程和使用协程。

无锁并发编程:多线程竞争锁时,会引起上下文切换,可以用一些方法来避免使用锁。

如:将数据的ID按照Hash算法取模分段,不同的线程处理不同的数据。

CAS算法:java的Atomic包使用CAS算法来更新数据,不需加锁。

使用最少线程:避免创建不必要的线程,这样就不会造成大量线程处于等待状态。

协成:在单线程里实现多任务的调度,并在单线程里维持多个任务间的切换。

2.2 什么是死锁?

所谓死锁是指多个进程循环等待它方占有的资源,而无限期地僵持不去的局面。

死锁会带来什么样的影响?

一旦产生死锁,就会造成系统功能不可用。

避免死锁常用的方法:

避免一个线程同时获得多个锁。 避免一个线程在锁内同时占用多个资源,尽量保证每个锁只占用一个资源。

尝试使用定时锁,使用lock.tryLock(timeout)来替代使用内部锁机制。

对于数据库锁,加锁和解锁必须在一个数据库连接里,否则会出现解锁失败的情况。

2.3 什么是资源限制?

在并发编程时,程序的执行速度受限于计算机硬件资源或者软件资源。

硬件资源限制有带宽的上传和下载速度、硬件读写速度和CPU的处理速度。

软件资源限制有数据库的连接数和Socket连接数等。

资源限制引发的问题?

并发编程的原则是将代码中串行执行的部分变成并发执行,但是如果将某段串行的代码并发执行时,因为受限于资源,仍然在串行执行,程序不仅不会加快,反而会更慢。

如何解决资源限制问题?

对于硬件资源限制,如使用集群并行执行程序。例如使用ODPS、Hadoop或者自己搭建服务器集群,不同的机器处理不同的数据。

对于软件资源受限,如使用资源池将资源复用。例如使用连接池将数据库和Socket连接复用,或者在调用对方webservice接口获取数据时,建立一个连接。

3.什么是线程:

线程是现代操作系统调度的最小单位,又叫轻量级进程,在一个进程里可以创建多个线程,这些线程拥有各自的计数器、堆栈和局部变量等属性,并且能够访问共享的内存变量。处理器在这些线程上高速切换,让使用者感觉这些线程在同时执行。而一个java程序的运行不仅仅总是main()方法的运行,而是main线程和多个其他线程同时运行。

为什么要使用多线程?

1.随着处理器上的核心数量越来越多,现在大多数计算机都比以往更加擅长并行计算,如果程序使用多线程技术,将计算逻辑分配到多个处理器核心上,就会显著减少程序的处理时间,并且随着处理器核心的加入而变得更有效。

2.响应用户请求的线程能够尽可能快地处理完成,缩短了响应时间,提升了用户体验。

创建线程的目的:

为了开启一条执行路径,去运行指定的代码和其他代码实现并行运行。开启线程是为了运行指定代码,所以必须要有Thread类对象或是其子类对象。

4 创建线程的两种传统方式:

(继承Thread类,复写run()方法;单独实现Runnable接口然后把其对象传入Thread构造器,这两种方法都必须调用Start来开启线程)

4.1:创建Thread的子类,覆盖其中的run方法,运行这个子类的start方法即可开启线程

public static void main(String[] args) {

Thread thread = new Thread() {

@Override

public void run() { //重写run()方法

while (true) {

try {

Thread.sleep(500); //线程休眠500毫秒

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println("1" +Thread.currentThread().getName()); //得到当前线程

System.out.println("2" +Thread.currentThread().getName());

}

};

thread.start(); //启动线程

4.2 创建Thread时传递一个实现Runnable接口的对象实例

public static void main(String[] args) {

Thread thread2 = new Thread(new Runnable() { //传入一个Runnable接口的实例

@Override

public void run() { //重写run方法

while (true) {

try {

Thread.sleep(500); //线程休眠500毫秒

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println("4" +Thread.currentThread().getName()); //得到当前线程

System.out.println("3" +Thread.currentThread().getName());

}

}

});

thread2.start(); //启动线程

}

注:执行线程的时候可以使用start()方法或者是run()方法,虽然使用run方法会达到同样的效果,但是run是在主线程中使用的,也就是使用了当前的方法内线程,而不是另起一个线程,这样就达不到异步的效果。所以务必使用start()。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值