一.Object
一般来说Synchronized 同步锁就能解决大部分线程同步问题,但是如果情况比较复杂就不行了,这就得用Object的wait(),notify(),notifyAll()。但是这个三个函数只能实现不公平锁,Semaphore能够实现公平锁和不公平锁,后面再说。
概念
Synchronized:同步锁,指的是他能锁住对象、类、函数、代码块,使得同一时间这些东西只能被一个线程占用。
Object.wait():表示进入等待状态,使得当前线程当前代码段放弃Object的控制权(ps:sleep()不释放同步锁,wait()释放同步缩. )
Object.notify():单一通知,就是让随机一个处于等待状态的Object所处代码段所处线程重新获得这个Object的控制权。
Object.notifyAll():使得所有处于等待状态的Object的所处代码段所处线程重新获得这个Object的控制权。
注意:
这个Object的引用地址不能改变,Object引用的对象的内部参数可以改变。
然后使用这个三个函数的时候必须加上synchronized的同步锁,保持同步,
在线程A,一个对象在自己的同步锁代码块里执行了wait,然后这个对象在线程B执行了notify通知到线程A继续运行,这个时候原来的线程不是继续运行,而是重新把同步锁代码块从头到尾运行一遍。而且Object的wait函数能够停止当前线程的运行,但是不能实现一个代码段在同一时间只有一个线程执行,所以需要synchronized 来完成这个任务。
这个时候我们再构建一个生产者和消费者的关系,就是生产者生产产品给消费者消费,如果生产者的生产速度高于消费者的消费速度,那没问题,如果低于消费者的消费速度。消费者在得知没有产品了,他就只能等待,然后等到生产者生产出产品通知消费者,消费者再来消费。
其实这个关系我之前在NDK的pthread里说过,
http://blog.csdn.net/z979451341/article/details/79423618
因为这个三个函数都是调用底层c语言弄的,所以我找不到真正的源码,但是我可以告诉你和NDK的pthread没得跑
@FastNative
public final native void notify();
@FastNative
public final native void notifyAll();
@FastNative
public final native void wait() throws InterruptedException;
好了,我们先上例子代码,再来说说生产者和消费者的关系,和这个三个函数的使用情况
生产者
public class ProductThread extends Thread {
private DataBean dataBean;
private boolean state = true;
public void setState(boolean state){
this.state = state;
}
public ProductThread(String name, DataBean dataBean){
super(name);
this.dataBean = dataBean;
}
@Override
public void run(){
for(;state;){
try{
sleep(1000);
}catch (InterruptedException e){
e.printStackTrace();
}
synchronized (dataBean){
dataBean.setId(dataBean.getId()+1);
Log.v("zzw","product 1, now "+dataBean.getId());
dataBean.notify();
}
}
}
}
消费者
public class ConsumerThread extends Thread{
private DataBean dataBean;
private boolean state = true;
public void setState(boolean state){
this.state = state;
}
public ConsumerThread(String name, DataBean dataBean){
super(name);
this.dataBean = dataBean;
}
public void run(){
for(;state;){
try{
sleep(1000);
}catch (InterruptedException e){
e.printStackTrace();
}
synchronized (dataBean){
if(dataBean.getId() == 0){
Log.v("zzw",getName()+" wait");
try {
dataBean.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}else {
dataBean.setId(dataBean.getId() - 1);
Log.v("zzw",getName()+" consumer 1, now "+dataBean.getId());
}
}
}
}
}
主函数
public class FourActivity extends AppCompatActivity {
private Button btn;
DataBean dataBean;
private ConsumerThread consumer_one,consumer_two,consumer_three;
private ProductThread productThread;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_four);
dataBean = new DataBean();
dataBean.setId(0);
productThread = new ProductThread("product",dataBean);
consumer_one = new ConsumerThread("one",dataBean);
consumer_two = new ConsumerThread("two",dataBean);
consumer_three = new ConsumerThread("three",dataBean);
productThread.start();
consumer_one.start();
consumer_two.start();
consumer_three.start();
btn = (Button)findViewById(R.id.btn_one);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
productThread.setState(false);
consumer_one.setState(false);
consumer_two.setState(false);
consumer_three.setState(false);
}
});
}
}
我们看的出来生产者有一个,消费者有三个
生产速度小于消费速度
03-17 09:11:37.842 15782-15883/com.example.zth.seven V/zzw: product 1, now 1
03-17 09:11:37.844 15782-15884/com.example.zth.seven V/zzw: one consumer 1, now 0
03-17 09:11:37.844 15782-15885/com.example.zth.seven V/zzw: two wait
03-17 09:11:37.844 15782-15886/com.example.zth.seven V/zzw: three wait
03-17 09:11:38.842 15782-15883/com.example.zth.seven V/zzw: product 1, now 1
03-17 09:11:38.844 15782-15884/com.example.zth.seven V/zzw: one consumer 1, now 0
03-17 09:11:39.843 15782-15883/com.example.zth.seven V/zzw: product 1, now 1
03-17 09:11:39.843 15782-15885/com.example.zth.seven V/zzw: two consumer 1, now 0
03-17 09:11:39.844 15782-15884/com.example.zth.seven V/zzw: one wait
从log看得出第一轮值满足了一个消费者,另外两个等待,后面继续生产随机通知一个
当生产速度等于消费速度,并且让我们试一下notify与notifyAll的使用区别
修改一些生产者的代码
synchronized (dataBean){
dataBean.setId(dataBean.getId()+3);
Log.v("zzw","product 3, now "+dataBean.getId());
dataBean.notify();
}
结果
03-17 09:38:24.654 20465-20555/com.example.zth.seven V/zzw: product 3, now 3
03-17 09:38:24.654 20465-20556/com.example.zth.seven V/zzw: one consumer 1, now 2
03-17 09:38:24.654 20465-20557/com.example.zth.seven V/zzw: two consumer 1, now 1
03-17 09:38:24.654 20465-20558/com.example.zth.seven V/zzw: three consumer 1, now 0
03-17 09:38:25.655 20465-20556/com.example.zth.seven V/zzw: one wait
03-17 09:38:25.655 20465-20555/com.example.zth.seven V/zzw: product 3, now 3
03-17 09:38:25.655 20465-20558/com.example.zth.seven V/zzw: three consumer 1, now 2
03-17 09:38:25.655 20465-20557/com.example.zth.seven V/zzw: two consumer 1, now 1
03-17 09:38:26.655 20465-20555/com.example.zth.seven V/zzw: product 3, now 4
03-17 09:38:26.655 20465-20558/com.example.zth.seven V/zzw: three consumer 1, now 3
03-17 09:38:26.655 20465-20557/com.example.zth.seven V/zzw: two consumer 1, now 2
03-17 09:38:26.655 20465-20556/com.example.zth.seven V/zzw: one consumer 1, now 1
一开始三个消费者都可以去消费,就是第一个消费者因为抢在生产者生产之前就开始了第二轮消费,所以他就进入等待状态,因为第二轮生产没有随机通知到one,所以就剩下一个产品导致后面消费者一直都在消费没有进入等待状态。
修改生产者代码用notifyAll
synchronized (dataBean){
dataBean.setId(dataBean.getId()+3);
Log.v("zzw","product 3, now "+dataBean.getId());
dataBean.notifyAll();
}
看log
03-17 09:47:21.022 22561-22583/com.example.zth.seven V/zzw: one wait
03-17 09:47:21.022 22561-22585/com.example.zth.seven V/zzw: three wait
03-17 09:47:21.022 22561-22584/com.example.zth.seven V/zzw: two wait
03-17 09:47:21.022 22561-22582/com.example.zth.seven V/zzw: product 3, now 3
03-17 09:47:22.023 22561-22583/com.example.zth.seven V/zzw: one consumer 1, now 2
03-17 09:47:22.023 22561-22584/com.example.zth.seven V/zzw: two consumer 1, now 1
03-17 09:47:22.023 22561-22585/com.example.zth.seven V/zzw: three consumer 1, now 0
03-17 09:47:22.023 22561-22582/com.example.zth.seven V/zzw: product 3, now 3
03-17 09:47:23.023 22561-22583/com.example.zth.seven V/zzw: one consumer 1, now 2
03-17 09:47:23.024 22561-22585/com.example.zth.seven V/zzw: three consumer 1, now 1
03-17 09:47:23.024 22561-22584/com.example.zth.seven V/zzw: two consumer 1, now 0
03-17 09:47:23.024 22561-22582/com.example.zth.seven V/zzw: product 3, now 3
03-17 09:47:24.024 22561-22583/com.example.zth.seven V/zzw: one consumer 1, now 2
03-17 09:47:24.024 22561-22585/com.example.zth.seven V/zzw: three consumer 1, now 1
开始三个消费者先一步开始消费,因为这个时候生产者没有生成就进入等待,这个时候得提一句,之前基本都是第一轮生成者先生成的,因为是生产者的线程最先开启,但是这一回不同,因为notifyAll比notify要耗时很多,毕竟是通知所有等待。然后后面因为生成速度跟得上消费速度,所以消费者一直消费没有进入消费状态。这个时候我在想如果使用三个notify是不是比这一个notifyAll要好。
修改生成者代码
dataBean.setId(dataBean.getId()+3);
Log.v("zzw","product 3, now "+dataBean.getId());
dataBean.notify();
dataBean.notify();
dataBean.notify();
结果
03-17 09:54:40.775 23718-23785/com.example.zth.seven V/zzw: product 3, now 3
03-17 09:54:40.777 23718-23787/com.example.zth.seven V/zzw: two consumer 1, now 2
03-17 09:54:40.778 23718-23788/com.example.zth.seven V/zzw: three consumer 1, now 1
03-17 09:54:40.778 23718-23786/com.example.zth.seven V/zzw: one consumer 1, now 0
03-17 09:54:41.776 23718-23785/com.example.zth.seven V/zzw: product 3, now 3
03-17 09:54:41.778 23718-23787/com.example.zth.seven V/zzw: two consumer 1, now 2
03-17 09:54:41.778 23718-23788/com.example.zth.seven V/zzw: three consumer 1, now 1
03-17 09:54:41.778 23718-23786/com.example.zth.seven V/zzw: one consumer 1, now 0
03-17 09:54:42.777 23718-23785/com.example.zth.seven V/zzw: product 3, now 3
03-17 09:54:42.778 23718-23787/com.example.zth.seven V/zzw: two consumer 1, now 2
03-17 09:54:42.779 23718-23788/com.example.zth.seven V/zzw: three consumer 1, now 1
03-17 09:54:42.779 23718-23786/com.example.zth.seven V/zzw: one consumer 1, now 0
果然三个notify比notifyAll要好
结论:notifyAll很耗时,可以用几个notify来代替,当然线程数量多了不敢保证,然后就是notify或者notifyAll通知wait,会让Object所处线程重新运行
还有几个生成者对应几个消费者的情况,因为得到的结论一样,大家只用跟着再创建几个生成者线程,并放入同一个Object就可以了,然后你们自己玩耍
附加一个阿里面试题的解法
题目:多线程,5个线程内部打印hello和world,hello在前,要求提供一种方法使得5个线程先全部打印出hello后再打印5个word。
答案:说白了就是通过一个实体类记录几个线程执行打印hello,在打印word之前判断目前是否有五个线程都打印了hello,如果不是就调用wait等待,如果是的就调用notifyAll通知所有线程,重新执行同步锁的代码,此时满足条件继续执行代码,打印world
public class TestThread extends Thread {
TestBean bean;
public TestThread(TestBean bean) {
super();
this.bean = bean;
}
@Override
public void run() {
super.run();
Log.v("zzw",Thread.currentThread()+"hello");
bean.setNum(bean.getNum()+1);
synchronized (bean) {
if (bean.getNum() >= 5) {
bean.notifyAll();
} else {
try {
bean.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Log.v("zzw",Thread.currentThread()+"world");
}
}
public class TestBean {
private int num;
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
}
public class FourActivity extends AppCompatActivity {
TestThread one, two, three, four, five;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_four);
TestBean bean = new TestBean();
bean.setNum(0);
one = new TestThread(bean);
two = new TestThread(bean);
three = new TestThread(bean);
four = new TestThread(bean);
five = new TestThread(bean);
one.start();
two.start();
three.start();
four.start();
five.start();
}
}
二.semaphore
Semaphore可以根据情况来让一个代码段在同一时间只有一个线程执行,但是不能直接执行停止线程。
Semaphore,计数信号量,之所以要说这,因为之前的Object三个函数只实现了不公平的线程同步(随机让一个等待线程开启),而Semaphore能够实现公平的线程同步(让等待时间最长的线程开启),而且不用synchronize来实现线程堵塞。
Semaphore是通过控制类似许可证的数量来完成控制线程数量。
初始化Semaphore,规定正在运行的线程数量,这是规定了3为最大许可证数量(
Semaphore semaphore = new Semaphore(3);
上面创建的是公平模式,还有不公平模式
public Semaphore(int permits, boolean fair)
当我们运行线程的run函数时,请求许可证,如果当前运行的线程数量比最大线程数少,他就会允许这个线程运行,同时计算已用许可证的变量加一,否则堵塞线程。
semaphore.acquire();
还有就是这个acquire函数可以传入整数,也就是一个线程可以获取几个许可证,不过如果最大许可证数量为10,你执行acquire(3),那个线程最多三个同时运行,毕竟10/3=3
semaphore.acquire(3);
当run函数运行完毕,释放许可证,已用许可证的变量建议
semaphore.release();
减少当前可用许可证的数量,也就是增加已用许可证的数量
protected void reducePermits(int reduction)
获取剩余许可证的数量
public int drainPermits()
我首先演示一下使用Semaphore的过程
首先编写线程代码,其中线程构造函数传入Semaphore对象并给线程取名字,便于后期识别
public class TestThread extends Thread{
Semaphore semaphore;
TestThread (String name,Semaphore semaphore) {
super(name);
this.semaphore = semaphore;
}
@Override
public void run() {
try {
// 从信号量中获取一个允许机会
semaphore.acquire();
Log.v("zzw",Thread.currentThread().getName() + " start at " + System.currentTimeMillis());
Thread.sleep(1000);
Log.v("zzw",Thread.currentThread().getName() + " stop at " + System.currentTimeMillis());
// 释放允许,将占有的信号量归还
semaphore.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
开启10个线程,设置一个最大许可证数为3的Semaphore
public class OneActivity extends Activity {
Semaphore semaphore = new Semaphore(3);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.one);
Button btn_one = (Button) findViewById(R.id.btn_one);
btn_one.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
for (int i = 0; i < 10; i++) {
new TestThread(i+"",semaphore).start();
}
}
});
}
}
结果,开启的10个线程,都是按照开启顺序获取许可证取运行的
05-13 16:22:01.363 5038-5146/zzw.myapplication V/zzw: 1 start at 1526199721363
05-13 16:22:01.364 5038-5149/zzw.myapplication V/zzw: 2 start at 1526199721364
05-13 16:22:01.364 5038-5145/zzw.myapplication V/zzw: 0 start at 1526199721364
05-13 16:22:02.363 5038-5146/zzw.myapplication V/zzw: 1 stop at 1526199722363
05-13 16:22:02.364 5038-5150/zzw.myapplication V/zzw: 3 start at 1526199722364
05-13 16:22:02.364 5038-5149/zzw.myapplication V/zzw: 2 stop at 1526199722364
05-13 16:22:02.364 5038-5145/zzw.myapplication V/zzw: 0 stop at 1526199722364
05-13 16:22:02.364 5038-5151/zzw.myapplication V/zzw: 4 start at 1526199722364
05-13 16:22:02.365 5038-5152/zzw.myapplication V/zzw: 5 start at 1526199722365
05-13 16:22:03.364 5038-5150/zzw.myapplication V/zzw: 3 stop at 1526199723364
05-13 16:22:03.364 5038-5153/zzw.myapplication V/zzw: 6 start at 1526199723364
05-13 16:22:03.365 5038-5151/zzw.myapplication V/zzw: 4 stop at 1526199723365
05-13 16:22:03.365 5038-5152/zzw.myapplication V/zzw: 5 stop at 1526199723365
05-13 16:22:03.365 5038-5154/zzw.myapplication V/zzw: 7 start at 1526199723365
05-13 16:22:03.366 5038-5155/zzw.myapplication V/zzw: 8 start at 1526199723366
05-13 16:22:04.365 5038-5153/zzw.myapplication V/zzw: 6 stop at 1526199724364
05-13 16:22:04.365 5038-5156/zzw.myapplication V/zzw: 9 start at 1526199724365
05-13 16:22:04.366 5038-5154/zzw.myapplication V/zzw: 7 stop at 1526199724366
05-13 16:22:04.366 5038-5155/zzw.myapplication V/zzw: 8 stop at 1526199724366
05-13 16:22:05.366 5038-5156/zzw.myapplication V/zzw: 9 stop at 1526199725366
如果我们把Semaphore改成非公平模式
Semaphore semaphore = new Semaphore(3,false);
结果看起来还是比较有序,毕竟创建和开启线程需要一定的时间,但是这里可以看得到线程6明显排在后头了
05-13 16:54:00.585 12612-13069/zzw.myapplication V/zzw: 2 start at 1526201640584
05-13 16:54:00.585 12612-13068/zzw.myapplication V/zzw: 1 start at 1526201640585
05-13 16:54:00.585 12612-13066/zzw.myapplication V/zzw: 0 start at 1526201640585
05-13 16:54:01.586 12612-13069/zzw.myapplication V/zzw: 2 stop at 1526201641586
05-13 16:54:01.586 12612-13068/zzw.myapplication V/zzw: 1 stop at 1526201641585
05-13 16:54:01.586 12612-13066/zzw.myapplication V/zzw: 0 stop at 1526201641586
05-13 16:54:01.586 12612-13070/zzw.myapplication V/zzw: 3 start at 1526201641586
05-13 16:54:01.586 12612-13071/zzw.myapplication V/zzw: 4 start at 1526201641586
05-13 16:54:01.587 12612-13072/zzw.myapplication V/zzw: 5 start at 1526201641587
05-13 16:54:02.586 12612-13070/zzw.myapplication V/zzw: 3 stop at 1526201642586
05-13 16:54:02.586 12612-13071/zzw.myapplication V/zzw: 4 stop at 1526201642586
05-13 16:54:02.587 12612-13074/zzw.myapplication V/zzw: 7 start at 1526201642587
05-13 16:54:02.588 12612-13072/zzw.myapplication V/zzw: 5 stop at 1526201642588
05-13 16:54:02.588 12612-13075/zzw.myapplication V/zzw: 8 start at 1526201642588
05-13 16:54:02.589 12612-13073/zzw.myapplication V/zzw: 6 start at 1526201642589
05-13 16:54:03.588 12612-13074/zzw.myapplication V/zzw: 7 stop at 1526201643588
05-13 16:54:03.589 12612-13076/zzw.myapplication V/zzw: 9 start at 1526201643589
05-13 16:54:03.589 12612-13075/zzw.myapplication V/zzw: 8 stop at 1526201643589
05-13 16:54:03.589 12612-13073/zzw.myapplication V/zzw: 6 stop at 1526201643589
05-13 16:54:04.589 12612-13076/zzw.myapplication V/zzw: 9 stop at 1526201644589
3.ReentrantLock
Lock既可以保证代码段在同一时间只有一个线程执行,并且堵塞线程和释放线程。
Lock的lock函数和unlock可以完成 代码段在在同一时间只有一个线程执行(RentrantLock必须是同一个对象)
我这里直接上代码和其log结果
public class MyThread extends Thread {
ReentrantLock lock;
MyThread(ReentrantLock lock, String name){
super(name);
this.lock=lock;
}
@Override
public void run() {
super.run();
lock.lock();
for(int i=0;i<5;i++){
Log.v("zzw",getName()+" "+i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
lock.unlock();
}
}
ReentrantLock lock=new ReentrantLock();
Condition condition=lock.newCondition();
for(int i=0;i<5;i++){
MyThread one=new MyThread(lock,""+i);
one.start();
}
10-15 09:22:39.618 9097-9152/? V/zzw: 1 0
10-15 09:22:40.619 9097-9152/bitpai.com.two V/zzw: 1 1
10-15 09:22:41.620 9097-9152/bitpai.com.two V/zzw: 1 2
10-15 09:22:42.621 9097-9152/bitpai.com.two V/zzw: 1 3
10-15 09:22:43.622 9097-9152/bitpai.com.two V/zzw: 1 4
10-15 09:22:44.623 9097-9154/bitpai.com.two V/zzw: 3 0
10-15 09:22:45.625 9097-9154/bitpai.com.two V/zzw: 3 1
10-15 09:22:46.626 9097-9154/bitpai.com.two V/zzw: 3 2
10-15 09:22:47.626 9097-9154/bitpai.com.two V/zzw: 3 3
10-15 09:22:48.627 9097-9154/bitpai.com.two V/zzw: 3 4
10-15 09:22:49.629 9097-9151/bitpai.com.two V/zzw: 0 0
10-15 09:22:50.631 9097-9151/bitpai.com.two V/zzw: 0 1
10-15 09:22:51.632 9097-9151/bitpai.com.two V/zzw: 0 2
10-15 09:22:52.633 9097-9151/bitpai.com.two V/zzw: 0 3
10-15 09:22:53.634 9097-9151/bitpai.com.two V/zzw: 0 4
10-15 09:22:54.636 9097-9153/bitpai.com.two V/zzw: 2 0
10-15 09:22:55.637 9097-9153/bitpai.com.two V/zzw: 2 1
10-15 09:22:56.638 9097-9153/bitpai.com.two V/zzw: 2 2
10-15 09:22:57.639 9097-9153/bitpai.com.two V/zzw: 2 3
10-15 09:22:58.639 9097-9153/bitpai.com.two V/zzw: 2 4
10-15 09:22:59.641 9097-9155/bitpai.com.two V/zzw: 4 0
10-15 09:23:00.642 9097-9155/bitpai.com.two V/zzw: 4 1
10-15 09:23:01.643 9097-9155/bitpai.com.two V/zzw: 4 2
10-15 09:23:02.644 9097-9155/bitpai.com.two V/zzw: 4 3
10-15 09:23:03.645 9097-9155/bitpai.com.two V/zzw: 4 4
如果给每一个Thread不同的ReentrantLock对象
for(int i=0;i<5;i++){
Log.v("zzw",getName()+" "+i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
log如下,各个线程的运行互不影响
10-17 18:47:13.042 10650-10703/? V/zzw: 3 0
10-17 18:47:13.042 10650-10704/? V/zzw: 4 0
10-17 18:47:13.042 10650-10701/? V/zzw: 1 0
10-17 18:47:13.043 10650-10702/? V/zzw: 2 0
10-17 18:47:13.043 10650-10700/? V/zzw: 0 0
10-17 18:47:14.043 10650-10701/bitpai.com.two V/zzw: 1 1
10-17 18:47:14.043 10650-10704/bitpai.com.two V/zzw: 4 1
10-17 18:47:14.043 10650-10703/bitpai.com.two V/zzw: 3 1
10-17 18:47:14.043 10650-10700/bitpai.com.two V/zzw: 0 1
10-17 18:47:14.044 10650-10702/bitpai.com.two V/zzw: 2 1
10-17 18:47:15.044 10650-10703/bitpai.com.two V/zzw: 3 2
10-17 18:47:15.044 10650-10704/bitpai.com.two V/zzw: 4 2
10-17 18:47:15.044 10650-10702/bitpai.com.two V/zzw: 2 2
10-17 18:47:15.044 10650-10700/bitpai.com.two V/zzw: 0 2
10-17 18:47:15.044 10650-10701/bitpai.com.two V/zzw: 1 2
10-17 18:47:16.044 10650-10703/bitpai.com.two V/zzw: 3 3
10-17 18:47:16.045 10650-10700/bitpai.com.two V/zzw: 0 3
10-17 18:47:16.045 10650-10702/bitpai.com.two V/zzw: 2 3
10-17 18:47:16.045 10650-10704/bitpai.com.two V/zzw: 4 3
10-17 18:47:16.045 10650-10701/bitpai.com.two V/zzw: 1 3
10-17 18:47:17.045 10650-10703/bitpai.com.two V/zzw: 3 4
10-17 18:47:17.045 10650-10700/bitpai.com.two V/zzw: 0 4
10-17 18:47:17.045 10650-10704/bitpai.com.two V/zzw: 4 4
10-17 18:47:17.045 10650-10701/bitpai.com.two V/zzw: 1 4
10-17 18:47:17.045 10650-10702/bitpai.com.two V/zzw: 2 4
Lock可以创建Condition对象,以此来完成线程的堵塞和释放,这个Condition与之前说的Object具有同样的能力
还是继续贴代码和log结果
public class MyThread extends Thread {
ReentrantLock lock;
Condition condition;
MyThread(ReentrantLock lock, String name,Condition condition){
super(name);
this.lock=lock;
this.condition=condition;
}
@Override
public void run() {
super.run();
lock.lock();
for(int i=0;i<5;i++){
Log.v("zzw",getName()+" "+i);
if(i==2){
try {
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
lock.unlock();
}
public void release(){
lock.lock();
condition.signal();//需要注意condition使用的时候前后一定要 Lock上锁和解锁
lock.unlock();
}
}
ReentrantLock lock=new ReentrantLock();
Condition condition=lock.newCondition();
final MyThread one=new MyThread(lock,"one",condition);
one.start();
Button btn=(Button)findViewById(R.id.btn);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
one.release();
}
});
在打印出2的时候停住了,然后再点击一次按钮,继续弹出3、4
10-15 09:37:23.128 12880-12927/bitpai.com.two V/zzw: one 0
10-15 09:37:24.129 12880-12927/bitpai.com.two V/zzw: one 1
10-15 09:37:25.131 12880-12927/bitpai.com.two V/zzw: one 2
10-15 09:37:32.094 12880-12927/bitpai.com.two V/zzw: one 3
10-15 09:37:33.094 12880-12927/bitpai.com.two V/zzw: one 4
4.Callable、Future和FutureTask
这三个主要是为了方便返回子线程的结果,但是对于什么是否返回结果不能对齐进行监控
Callable:一个拥有返回值的Runnable。
Future和FutureTask:用于获取Callable的运行状态,比如是否正在运行,是否运算接受,还用于接受Callable的返回值
Future.isDone() :判断任务是否执行完
Future.isCanlled():判断任务是否取消了
Future.get():获取返回值,如果任务还没执行完,会堵塞当前线程,所以经常需要和isDone()配合使用
Future.cancel():取消执行任务,但是如果任务已经在执行了,就会让他继续执行
Future配合Callable如下
public class TwoActivity extends AppCompatActivity {
ExecutorService executorService= Executors.newCachedThreadPool();
Task task=new Task();
Future<Integer> result;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_two);
result=executorService.submit(task);
((Button)findViewById(R.id.btn)).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(result.isDone()){
try {
Log.v("zzw","结果为"+result.get());
} catch (ExecutionException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}else {
Log.v("zzw","还在计算");
}
}
});
}
class Task implements Callable<Integer> {
@Override
public Integer call() throws Exception {
Thread.sleep(3000);
int sum = 0;
for (int i = 0; i < 100; i++)
sum += i;
return sum;
}
}
}
FutureTask和Future差不多,只是它直接包装了Callable
public class TwoActivity extends AppCompatActivity {
ExecutorService executorService= Executors.newCachedThreadPool();
Task task=new Task();
FutureTask<Integer> futureTask=new FutureTask<Integer>(task);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_two);
executorService.submit(futureTask);
((Button)findViewById(R.id.btn)).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(futureTask.isDone()){
try {
Log.v("zzw","结果为"+futureTask.get());
} catch (ExecutionException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}else {
Log.v("zzw","还在计算");
}
}
});
}
class Task implements Callable<Integer> {
@Override
public Integer call() throws Exception {
Thread.sleep(3000);
int sum = 0;
for (int i = 0; i < 100; i++)
sum += i;
return sum;
}
}
}