Android多线程研究(4)——从一道面试题说起

有一道这样的面试题:开启一个子线程和主线程同时运行,子线程输出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()方法的作用由此可见,它会让其他线程等待该线程执行完毕后再执行。






  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
当涉及到 Android 多线程面试题时,以下是一些常见的问题和答案: 1. 什么是线程和进程? - 进程是计算机中运行的程序的实例,它有自己的内存空间和资源。 - 线程是进程中的执行单位,一个进程可以有多个线程,共享进程的资源。 2. 为什么在 Android 中使用多线程? - 在 Android 应用中使用多线程可以提高性能和响应速度。 - 长时间运行的任务可以在后台线程中执行,避免阻塞主线程。 3. Android 中实现多线程的方式有哪些? - 使用 Thread 类创建新线程。 - 使用 AsyncTask 类在后台执行异步任务。 - 使用 HandlerThread 类在后台处理消息。 - 使用线程池来管理和复用线程。 4. 什么是 ANR(Application Not Responding)? - ANR 是指应用程序无法在一定时间内响应用户输入的情况。 - 当主线程被长时间阻塞时,系统会弹出 ANR 对话框,提示用户应用程序停止响应。 5. 如何避免在主线程中执行耗时操作? - 将耗时操作放在后台线程中执行,例如使用异步任务或线程池。 - 使用 Handler 或 HandlerThread 处理异步操作的结果。 6. 什么是线程同步和线程安全? - 线程同步是指在多个线程访问共享资源时,保证数据的一致性和正确性。 - 线程安全是指在多线程环境下,对共享资源的访问不会导致数据错误或不一致。 这些问题只是多线程面试中的一部分,还有其他更深入的问题可以探讨。希望这些答案能帮助到您,祝您面试顺利!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值