多线程

1、

①通过调用start()并不是立即运行线程,只是线程变成了可运行状态,并不是执行状态,什么时候运行多线程,是由操作系统决定的




②创建一个类并继承thread,重新run方法


通过start开启run方法


③实现runnable并重写run方法


创建runnable对象,并作为参数传递到thread中,通过start方法进行开启



2、两种启动线程方法的区别

1)共同点

都需要调用thread类产生线程,然后调用start()开启线程

2)不同点

①java是单继承模式,为了弥补这个缺点,通过实现runnable来弥补这个缺点。同时implements这种方式又比继承更加灵活。

②继承thread类就必须产生相应多个线程,而implements runnable接口则不同,只需要创建一个实现这个类的实例,然后用这个实例对象产生多个线程,就实现了整个资源的共享

3、start方法和run方法的区别

用start方法来启动线程,真正实现了多线程运行,这时无需等待run方法体代码执行完毕而直接继续执行下面的代码。通过调用Thread类的 start()方法来启动一个线程,这时此线程处于就绪(可运行)状态,并没有运行,一旦得到cpu时间片,就开始执行run()方法,这里方法 run()称为线程体,它包含了要执行的这个线程的内容,Run方法运行结束,此线程随即终止。


4、


②synchronized关键字,给对象加锁,synchronized对象锁

下面这两种方法的作用是一样的


③synchronized来实现线程间通信


两个线程都使用了MyObject,可以称为共享内存式通信,多个线程通过访问同一个共享变量。

threadA和ThreadB谁获取到了Object,谁就获取到的锁,谁就获取到了可执行权限,就可以进行线程代码的执行。

通过不同的线程去共享同一个变量,来进行锁的管理

④synchronized、volatile



i1的值只是做了一个简单的返回,有可能一个线程改变了il的值,另一个线程又来获取,两个线程获取到的i1的值是不一样的。根本原因是java当中有一个主内存的机制,其实就是一个缓存机制,使用这个主内存,可以保存这个变量当前正确的值,同时线程又可以将主内存中的值拷贝到自己独立的内存当中,这就是线程的一个优势所在。它有独立的内存,当它有独立的内存之后,这些线程的内存拷贝可能和刚才提到的这些主缓存中的值不同,所以,实际当中可能发生这样的情况,比如说主内存当中i1的值是1,而线程1或者线程b同时更改了线程的值,但是它没有把更新的值传回我们的主内存,或者没有通知其它线程我已经更改了i1的值,由于没有通知,没有通知的线程a或线程b中的值仍是2,这是它没有和主内存进行一个同步,这是没有用volitile关键字所引起的第一个问题。


volitile int i2,被关键字volitile修饰,这样就可以从主内存中直接获取volitile的值,意思是你从线程a或线程b去读取i2的值的时候,获取的都是主内存中的值。而不是不同线程当中的值。使用了volitile,即使使用了多线程,也不会把它的变量拷贝到相应的线程中的空间当中,这就是与没有使用volitile这个关键字的i1这个变量的最大最大的区别。所以说,使用了volitile关键字的变量,将会在所有线程当中同步获得数据。修改了i2的值,所有的线程都会得到通知,i2会同步进行更改。


synchronized修饰方法,synchronized获取或释放都有一个监听器monitor,如果两个线程都使用了同一个monitor,那么这个monitor就可以强制在一个时候只有一个线程可以处理这个代码块。第一,假设监听器没有锁住,如果锁住的话只能等待直到监听器解锁才能获取它的对象锁。第二,线程内存更新所有的变量,也就是说它会读取主内存中的变量,使自己的变量保证有效,意思就是同步主内存中的数据。第三,代码块就被执行,这里执行的就是return i3,这句话执行完之后会把任何的更改返回给主内存。最后一步,线程会释放对象锁给我们的monitor监听器。


这就是synchronized的关键字和volitile关键字不同的地方。


volitile只能在线程内存和主内存中同步一个变量的值,而synchronized在线程内存和主内存中同步所有变量的值。并且可以通过锁管理整个的变量。但是synchronized性能上比volitile有更大的消耗。


⑤synchronized/lock

synchronized:在需要同步的变量中加入这个控制,可以加在代码上,也可以加在指定的代码块上,在括号中可以指明所要锁住的对象。

lock:需要指定起始位置和终止位置,通过子类的lock和unlock方法来执行锁的开启和关闭,为了做到健壮性,一般还需要在finally中执行unlock,以防止死锁。

synchronized使用的是悲观锁机制,也就是线程获取的是独占的锁,独占的锁意味着其它的线程只能通过阻塞来等待线程释放锁。而lock采用的是乐观锁的方法,乐观锁就是每次不加锁,假设没有冲突,然后就去完成某样操作。如果有冲突失败,就重试,直到成功为止。

⑥sleep/wait

sleep:在特定时间内,阻塞线程的执行,但是不会改变线程的锁的持有情况。

wait:需要锁来控制的。


wait方法是定义在object大类当中的,需要在同步代码块中来调用,调用完之后会释放锁,并进入锁对象的等待队列。需要其它线程调用notify这个方法之后,才能重新竞争这个锁。notifyall,通知所有线程释放锁

5、线程池

1)好处:


①降低资源消耗:重复利用已经创建好的线程,降低线程创建、销毁带来的消耗

②提高响应速度:当任务达到一定数量程度的时候,可以不需要等待线程创建就立即执行

③提高线程的可管理性:线程毕竟还是比较稀缺的资源,尤其是在手机当中,无限制地创建线程,不仅会消耗系统资源,同时还会降低系统的稳定性,使用线程池可以进行统一的分配。这样不仅可以合理利用线程池,也提高了线程池的管理性

6、ThreadPoolExecutor


corePoolSize:线程池的基本大小

maximumPoolSize:线程池最大所能容纳的线程数

keepAliveTime:保存存活的时间

milliseconds:时间单位

runnableTaskQueue:线程的队列

handler:当队列和线程池都满了,就处于饱和状态,就需要使用一种策略进行处理。当线程池都满的时候,需要使用一种策略来告诉调用者。可以抛出异常,也可以不处理


线程池执行完毕后没有返回值,所以无法确定任务是否执行成功



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值