有一道这种面试题:开启一个子线程和主线程同一时候运行,子线程输出10次后接着主线程输出100次,如此重复50次。先看以下代码:

package com.maso.test;

/**
*
* @author Administrator
* 两个线程,当中是一个主线程,第一个线程先运行输出10次,主线程接着运行输出100次,如此重复50次
*/
public class ThreadTest3 implements Runnable{
private static Test test;
@Override
public void run() {
for(int i=0; i<50; i++){
test.f1(i);
}
} public static void main(String[] args) {
test = new Test();
new Thread(new ThreadTest3()).start();
for(int i=0; i<50; i++){
test.f2(i);
}
} /**
* 将控制和逻辑及数据分类(该类就是数据)
* @author Administrator
*
*/
static class Test{
private boolean isf1 = true;
/**
* 输出10次
*/
public synchronized void f1(int j){
if(!isf1){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
for(int i=1; i<=10; i++){
System.out.println(Thread.currentThread().getName() + "第" + j + "次轮巡,输出" + i);
}
isf1 = false;
notify();
} /**
* 输出100次
*/
public synchronized void f2(int j){
if(isf1){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
for(int i=1; i<=100; i++){
System.out.println(Thread.currentThread().getName() + "第" + j + "次轮巡,输出" + i);
}
isf1 = true;
notify();
}
}
}

上面推断用的是if语句,这样做看似没有什么问题,实际上这样做是不安全的,由于线程在等待的过程中有可能被假唤醒,所以我们须要使用while语句。另外在使用wait和notify的时候须要注意一下几点:

1、调用object的wait方法和notity方法时,必须先获得object的对象锁(必须写在synchronized中)。

2、假设调用了object的wait方法,则该线程就放掉了对象锁。

3、假设A1、A2、A3都在object.wait(),则B调用object.notify()仅仅能唤醒A1、A2、A3中的一个(详细哪一个由JVM决定)

4、object.notifyAll()能够唤醒所有。

5、B在唤醒A的时候,B假设还持有对象锁,则要等到B释放锁后,A才有机会运行。

Sleep和Wait有什么差别?

sleep()并不释放对象锁,wait()释放对象锁。可是wait()和sleep()都能够通过interrupt()方法打断线程的暂停状态,从而使线程立马抛出InterruptedException。假设线程A希望马上结束线程B,则能够对线程B相应的Thread实例调用interrupt方法。假设此刻线程B正在wait/sleep/join,则线程B会立马抛出InterruptedException,在catch() {} 中直接return就可以安全地结束线程。须要注意的是,InterruptedException是线程自己从内部抛出的,并非interrupt()方法抛出的。对某一线程调用interrupt()时,假设该线程正在运行普通的代码,那么该线程根本就不会抛出InterruptedException。可是,一旦该线程进入到wait()/sleep()/join()后,就会立马抛出InterruptedException。

以下我们来看看线程的生命周期:

实现线程调度的方法例如以下:

1、sleep():该线程是让线程休眠一定的时间,须要捕获InterruptedException

2、yield():暂停当前线程,让同等级优先权的线程运行,假设没有同等级优先权线程则不会起作用。起作用后会让出CPU运行时间,进入就绪状态。

3、join():让一个线程等待调用join方法的线程运行完成后再继续运行。

看一段代码:

public class ThreadTest4 implements Runnable{
private static int a = 0;
@Override
public void run() {
for(int i=0; i<10; i++){
a++;
}
} public static void main(String[] args) {
new Thread(new ThreadTest4()).start();
System.out.println(a);
}
}

这段代码会输出10吗?答案是不会的,由于在启动子线程后,就立马输出了a的值,此时子线程对a还没有操作。改动例如以下:

public class ThreadTest4 implements Runnable{
private static int a = 0;
@Override
public void run() {
for(int i=0; i<10; i++){
a++;
}
} public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(new ThreadTest4());
t.start();
t.join();
System.out.println(a);
}
}

这回输出了10,join()方法的作用由此可见,它会让其它线程等待该线程运行完成后再运行。

Android多线程研究(4)——从一道面试题说起的更多相关文章

  1. Android多线程研究(6)——多线程之间数据隔离

    在上一篇<Android多线程研究(5)--线程之间共享数据>中对线程之间的数据共享进行了学习和研究,这一篇我们来看看怎样解决多个线程之间的数据隔离问题,什么是数据隔离呢?比方说我们如今开 ...

  2. Android多线程研究(5)——线程之间共享数据

    一.如果是每个线程都执行相同的代码,则可以使用同一个Runnable来实现共享 public class MultiThreadShareData { public static void main( ...

  3. Android多线程研究(1)——线程基础及源代码剖析

    从今天起我们来看一下Android中的多线程的知识,Android入门easy,可是要完毕一个完好的产品却不easy,让我们从线程開始一步步深入Android内部. 一.线程基础回想 package ...

  4. Android多线程研究(1)——线程基础及源码剖析

    从今天起我们来看一下Android中的多线程的知识,Android入门容易,但是要完成一个完善的产品却不容易,让我们从线程开始一步步深入Android内部. 一.线程基础回顾 package com. ...

  5. Android多线程研究(2)——定时器

    先来看一段代码: public static void main(String[] args) { new Timer().schedule(new TimerTask() { @Override p ...

  6. Android多线程研究(3)——线程同步和相互排斥及死锁

    为什么会有线程同步的概念呢?为什么要同步?什么是线程同步?先看一段代码: package com.maso.test; public class ThreadTest2 implements Runn ...

  7. Android多线程研究(9)——读写锁

    一.什么是锁 在Java的util.concurrent.locks包下有关于锁的接口和类如下: 先看一段代码: package com.codeing.snail.test; public clas ...

  8. Android多线程研究(8)——Java中的原子性理解

    一.什么是原子性 原子性是世界上最小单位,具有不可分割性.比如a=0;(a非long和double类型)这个操作是不可分割的,那么我们说这个操作是原子操作.再比如:a++;这个操作实际上是a=a+1; ...

  9. Android多线程研究(9)——线程锁Lock

    在前面我们在解决线程同步问题的时候使用了synchronized关键字,今天我们来看看Java 5.0以后提供的线程锁Lock. Lock接口的实现类提供了比使用synchronized关键字更加灵活 ...

随机推荐

  1. 如何用 Retrofit 2 在安卓上实现 HTTP 访问?

    最近,笔者对安卓开发的兴趣愈发浓厚,而且不断尝试了许多传闻很棒的开发库 -- 大部分也真的很不错.于是打算写一个系列文章,介绍使用这些让人惊叹的库建立安卓示例应用的实践.这样,读者可以自行判断,这些库 ...

  2. node.js + gulp用JENKINS作CI编译

    这里还是有点坑,要注意. 安装NODE.JS不说,GULP绿色化也不说. 但要让JENKINS识别环境变量. /etc/profile.... export NODE_HOME=/usr/local/ ...

  3. php Magic methods __call

    <?php class Car{ protected $_color; protected $_model; public function __call($name,$arguments){ ...

  4. 2013年最受欢迎的16个HTML5 WordPress主题

    本文中,我整理了16个最新.最受欢迎的WordPress主题,它们一致的特征是支持HTML5, 它们秉承最佳设计理念以及最新的流行趋势,将它们归纳与此,希望对喜欢HTML5,准备用WordPress做 ...

  5. ActionBar官方教程(2)选主题让应用支或不支持ActionBar及支持ActionBar的应用如何隐藏和显示

    Adding the Action Bar As mentioned above, this guide focuses on how to use the ActionBar APIs in the ...

  6. Hadoop中的各种排序

    本篇博客是金子在学习hadoop过程中的笔记的整理,不论看别人写的怎么好,还是自己边学边做笔记最好了. 1:shuffle阶段的排序(部分排序) shuffle阶段的排序可以理解成两部分,一个是对sp ...

  7. C#微信公众号开发系列教程(接收事件推送与消息排重)

    微信服务器在5秒内收不到响应会断掉连接,并且重新发起请求,总共重试三次.这样的话,问题就来了.有这样一个场景:当用户关注微信账号时,获取当前用户信息,然后将信息写到数据库中.类似于pc端网站的注册.可 ...

  8. 加快VisualStudio的开发速度--VS的一些开发技巧

    最近不得不使用VisualStudio来进行一些开发,用习惯了Eclipse,感觉VS很难上手,不过通过google,把VS进行Eclipse化,顺便记录下来,以防忘记. 1)显示文字的自动完成. 改 ...

  9. [swustoj 191] 迷宫逃离

    迷宫逃离(0191) 描述 江鸟突然想到了一个迷宫逃离的游戏,话说有三个人被困于一个n*m的迷宫里,他们三人都可以向上.向下.向左.向右四个方向进行走动,当然他们所在的初始位置没有障碍物,同时只能走到 ...

  10. 嵌入式linux中使用 DHCP功能描述

    嵌入式linux中使用 DHCP功能描述 busybox中udhcpc的默认script脚本地址为#define DEFAULT_SCRIPT   CONFIG_UDHCPC_DEFAULT_SCRI ...