




已阅读5页,还剩10页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Android进阶多线程系列之wait、notify、sleep、join、yield、synchronized关键字、ReentrantLock锁前言多线程一直是初学者最困惑的地方,每次看到一篇文章,觉得很有难度,就马上叉掉,不看了,我以前也是这样过来的。后来,我发现这样的态度不行,知难而退,永远进步不了。于是,我狠下心来看完别人的博客,尽管很难但还是咬着牙,不懂去查阅资料,到最后弄懂整个过程。虽然花费时间很大,但这就是自学的精髓,别人学不会,而我却学到了。很简单的一个例子,一开始我对自定义View也是很抵触,看到很难的图就不去思考他,故意避开它,然而当我看到自己喜欢的雷达图时,很有兴趣的去查阅资料,不知不觉,自定义View对我已经没有难度了。所以对于多线程我也是0基础,不过我还是咬着牙皮,该学的还是得学。这里先总结这几个类特点和区别,让大家带着模糊印象来学习这篇文章Thread是个线程,而且有自己的生命周期对于线程常用的操作有:wait(等待)、notify(唤醒)、notifyAll、sleep(睡眠)、join(阻塞)、yield(礼让)wait、notify、notifyAll都必须在synchronized中执行,否则会抛出异常synchronized关键字和ReentrantLock锁都是辅助线程同步使用的初学者常犯的误区:一个对象只有一个锁(正确的)线程同步之synchronized关键字马上就过年了,火车抢票又是一年沸沸扬扬的事情,这也就好比我们的多线程抢夺资源是一个道理,下面我们通过火车抢票的案例来理解public class SyncActivity extends AppCompatActivity private int ticket = 10; Override protected void onCreate(Bundle savedInstanceState) super.onCreate(savedInstanceState); setContentView(R.layout.activity_sync); for (int i = 0; i 10; i+) new Thread() Override public void run() /买票 sellTicket(); .start(); public void sellTicket() ticket-; System.out.println(剩余的票数: + ticket); 这里我们通过开启十个线程来购买火车票,不过火车票只有十张,下面通过打印信息来看一下抢票的情况剩余的票数:9剩余的票数:8剩余的票数:7剩余的票数:6剩余的票数:5剩余的票数:1剩余的票数:1剩余的票数:1剩余的票数:1剩余的票数:0可以发现,票数出现了误差,这明显就是不行的,这也是因为开启了十个线程,大家都抢着自己的票。上面这种情况是因为其中有四个线程都挤在一起了,然后一起执行了【ticket;】,接着再一起执行【System.out.println(“剩余的票数:” + ticket);】导致的。那么该如何保证大家都是能够自觉排队,井然有序的抢票呢。这个时候就要用到synchronized关键字方法一:我们在方法上添加synchronized关键字public class SyncActivity extends AppCompatActivity private int ticket = 10; Override protected void onCreate(Bundle savedInstanceState) super.onCreate(savedInstanceState); setContentView(R.layout.activity_sync); for (int i = 0; i 10; i+) new Thread() Override public void run() /买票 sellTicket(); .start(); /添加在这里 public synchronized void sellTicket() ticket-; System.out.println(剩余的票数: + ticket); 这样就表示这个方法是同步的,只能由一个个线程来争夺里面的资源,下面通过打印信息可以验证剩余的票数:9剩余的票数:8剩余的票数:7剩余的票数:6剩余的票数:5剩余的票数:4剩余的票数:3剩余的票数:2剩余的票数:1剩余的票数:0方法二:我们在方法内添加synchronized关键字public class SyncActivity extends AppCompatActivity private int ticket = 10; Override protected void onCreate(Bundle savedInstanceState) super.onCreate(savedInstanceState); setContentView(R.layout.activity_sync); for (int i = 0; i 10; i+) new Thread() Override public void run() /买票 sellTicket(); .start(); /添加在这里 Object lock = new Object(); public void sellTicket() synchronized(lock) ticket-; System.out.println(剩余的票数: + ticket); 其实,synchronized关键字可以理解为一个锁,而锁就需要被锁的东西,所以synchronized又分为类锁和对象锁,即可以锁类又可以锁对象,它们共同的作用就是保证线程的同步。就好比如我们上面中synchronized(lock),就是对象锁,将Object对象锁起来一、类锁和对象锁的概念 对象锁和类锁在锁的概念上基本上和内置锁是一致的,但是在多线程访问时,两个锁实际是有很大的区别的,对象锁是用于对象实例方法,或者一个对象实例上的,类锁是用于类的静态方法或者一个类的class对象上的。我们知道,类的对象实例可以有很多个,但是每个类只有一个class对象,所以,结论是:1、不同对象实例的对象锁是互不干扰的,但是每个类只有一个类锁。2、而且类锁和对象锁互相不干扰。二、对象锁 类锁创建如下两种方法public class SynchronizedDemo /同步方法,对象锁 public synchronized void syncMethod() /同步块,对象锁 public void syncThis() synchronized (this) 三、类锁 对象锁创建如下两种方法public class SynchronizedDemo /同步class对象,类锁 public void syncClassMethod() synchronized (SynchronizedDemo.class) /同步静态方法,类锁 public static synchronized void syncStaticMethod() 四、通过例子理解结论和概念 根据类锁和对象锁的概念,我们来通过例子验证一下其正确性,这里演示两个对象锁和一个类锁,我们创建一个类public class SynchronizedDemo private int ticket = 10; /同步方法,对象锁 public synchronized void syncMethod() for (int i = 0; i 1000; i+) ticket-; System.out.println(Thread.currentThread().getName() + 剩余的票数: + ticket); /同步块,对象锁 public void syncThis() synchronized (this) for (int i = 0; i 1000; i+) ticket-; System.out.println(Thread.currentThread().getName() + 剩余的票数: + ticket); /同步class对象,类锁 public void syncClassMethod() synchronized (SynchronizedDemo.class) for (int i = 0; i 等待的时间: + (System.currentTimeMillis() - start); class WaitThread extends Thread O public void run() synchronized (lockObject) try /子线程等待了2秒钟后唤醒lockObject锁 Thread.sleep(2000); lockObject.notifyAll(); catch (InterruptedException e) e.printStackTrace(); 可以看到,我们使用的是同一个对象的锁,和同一个对象执行的wait()和notify()才会保证了我们的线程同步。当主线程执行到wait()方法时,代表主线程等待,让出使用权让子线程执行,这个时候主线程等待这一事件会被加进到【等待唤醒的队列】中。然后子线程则是两秒钟后执行notify()方法唤醒等待【唤醒队列中】的第一个线程,这里指的是主线程。而notifyAll()方法则是唤醒整个【唤醒队列中】的所有线程,这里就不多加演示了下面采用一道经典的Java多线程面试题来让大家练习熟悉熟悉:子线程循环10次,接着主线程循环15次,接着又回到子线程循环10次,接着再回到主线程又循环15次,如此循环50次/子线程new Thread() Override public void run() for (int i = 0; i 50; i+) for (int j = 0; j 子线程循环了 + (i + 1) + 次); .start();/主线程for (int i = 0; i 50; i+) for (int j = 0; j 主线程循环了 + (i + 1) + 次);首先是主要思路的搭建,现在的问题就是如何让子线程和主线程有序的执行呢,那肯定是我们的等待唤醒机制/子线程new Tread() Override public void run() for (int i = 0; i 50; i+) synchronized (lock) for (int j = 0; j 10; j+) System.out.println(子循环循环第 + (j + 1) + 次); /唤醒 lock.notify(); /等待 try lock.wait(); catch (InterruptedException e) e.printStackTrace(); .start();/主线程for (int i = 0; i 50; i+) synchronized (lock) /等待 try lock.wait(); catch (InterruptedException e) StackTrace(); for (int j = 0; j 15; j+) System.out.println(主循环循环第 + (j + 1) + 次); /唤醒 lock.notify(); 不管是主线程先运行还是子线程运行,两个线程只能同时进入synchronized (lock)一个锁中。由于是子线程先运行:1、当主线程先进入synchronized (lock)锁时,它就必须是等待,而子线程开始运行输出,输出后就唤醒主线程。2、当子线程先运行的话,那就直接输出,然后等待主线程的运行输出线程的sleep()、join()、yield()一、sleep() sleep()作用是让线程休息指定的时间,时间一到就继续运行,它的使用很简单try Thread.sleep(2000); catch (InterruptedException e) e.printStackTrace();二、join() join()作用是让指定的线程先执行完再执行其他线程,而且会阻塞主线程,它的使用也很简单public class JoinActivity extends AppCompatActivity Override protected void onCreate(Bundle savedInstanceState) super.onCreate(savedInstanceState); setContentView(R.layout.activity_join); /启动线程一 try MyThread myThread1 = new MyThread(线程一); myThread1.start(); myThread1.join(); catch (InterruptedException e) e.printStackTrace(); System.out.println(主线程需要等待); /启动线程二 try MyThread myThread2 = new MyThread(线程二); myThread2.start(); myThread2.join(); catch (InterruptedException e) e.printStackTrace(); System.out.println(主线程继续执行); class MyThread extends Thread public MyThread(String name) super(name); Override public void run() System.out.println(getName() + 在运行); try Thread.sleep(2000); catch (InterruptedException e) e.printStackTrace(); 这里就不解释了,看打印信息,你就能发现它的作用了线程一在运行主线程需要等待线程二在运行主线程继续执行三、yield() yield()的作用是指定线程先礼让一下别的线程的先执行,就好比公交车只有一个座位,谁礼让了谁就坐上去。特别注意的是:yield()会礼让给相同优先级的或者是优先级更高的线程执行,不过yield()这个方法只是把线程的执行状态打回准备就绪状态,所以执行了该方法后,有可能马上又开始运行,有可能等待很长时间public class YieldActivity extends AppCompatActivity Override protected void onCreate(Bundle savedInstanceState) super.onCreate(savedInstanceState); setContentView(R.layout.activity_yield); MyThread myThread1 = new MyThread(线程一); MyThread myThread2 = new MyThread(线程二); myThread1.start(); myThread2.start(); class MyThread extends Thread public MyThread
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 脑梗塞遗症的护理查房
- 远程培训A3作业
- 《西游记》讲课课件
- 《表达要得体》课件
- 新人入职汇报
- 急性左心衰病人护理查房
- 消毒和隔离技术规范解读
- 放疗病人教学护理查房
- 2025年招标采购从业人员专业技术能力考试(招标采购项目管理中级)冲刺试题及答案(山东菏泽)
- 腰椎骨折手术病人的护理
- 4.1夯实法治基础教学设计 2025-2026学年度九年级上册 道德与法治 统编版
- 连铸工岗位操作规程考核试卷及答案
- 2025兵团普通职工考试试题及答案
- 《中国老年危重患者营养支持治疗指南(2023)》解读 4
- 2025年广东国家公务员申论考试真题及答案-地市级
- 绿色矿山培训课件
- 国有企业十五五人力资源规划框架
- 无人机实操训练课件
- 十二大报告解读
- 格拉斯哥(GCS)昏迷评估量表(详xi操作)
- 肝硬化患者健康宣教知识
评论
0/150
提交评论