Java多线程学习及面试题

多线程
1.进程和线程

进程:受操作系统管理的基本单元(可以将一个exe理解为一个进程)

线程:进程中独立运行的子任务。

并发:同一时间执行不同的任务,任务来回切换

2.创建线程
2.1继承Thread
//继承Thread
public class MyThread extends Thread {
	@Override
	public void run() {
		super.run();
		System.out.println("搬砖");
	}
}

2.2实现Runnable接口
public class MyThread2 implements Runnable{
	@Override
	public void run() {
		// TODO Auto-generated method stub
		System.out.println("搬砖");
	}
}
3.线程API
方法描述
setName(String name)为线程设置名称
getName()获取线程名称
getId()获取线程的唯一标识
setPriority(int i)设置线程的优先级
4.线程生命周期
  1. 新生:线程类new出对象,此时内存中仅仅是为对象分配内存空间,为成员变量赋初始值。
  2. 就绪:调用线程start()方法后线程进入就绪状态,此时线程并不是立即执行,而是等待线程调度器分配时间片,当该线程得到资源后,调用线程run()方法
  3. 运行:线程run()方法运行时。
  4. 阻塞:当线程因为某些原因不能继续运行,并放弃所占用的处理器资源时,就进入阻塞状态,阻塞状态不能直接进入运行状态,而是当阻塞结束是,重新进入就绪状态,重新等待线程调度器分配资源。当出现如下情况时,线程进入阻塞。
    1. 线程调用sleep()方法时,当sleep()休眠时间结束时,线程进入就绪状态
    2. 线程调用阻塞式IO方法,在该方法返回之前,线程被阻塞
    3. 线程试图获得一个同步监视器,但是该监视器正在被其他线程持有
    4. 线程在等待某个notify()
  5. 死亡:run()方法执行完成,或者线程抛出异常
5.线程同步
5.1synchronized

非线程安全:多个线程访问同一对象实例变量时,出现读取结果不一致(或者称为脏度),就是非线程安全

  1. 同步方法
package cn.it.sy;
public class MyNumber {
	private int count = 0;

	// 当前对象
	public synchronized void change(String s) {
		try {// 原子性
			if (s.equals("a")) {
				count = 100;
				System.out.println("a set count over");
				Thread.sleep(2000);
			} else {
				count = 200;
				System.out.println("other set count over");
			}
			System.out.println(Thread.currentThread().getName() + "====" + count);
		} catch (InterruptedException e) {
			// TODO: handle exception
		}
	}

}

package cn.it.sy;

public class ThreadA extends Thread{
	
	private MyNumber myNumber;
	private String s;
	
	public ThreadA(MyNumber myNumber, String s) {
		super();
		this.myNumber = myNumber;
		this.s = s;
	}

	@Override
	public void run() {
		myNumber.change(s);//s="a"
	}
}

package cn.it.sy;

public class ThreadB extends Thread{
	
	private MyNumber myNumber;
	private String s;
	
	public ThreadB(MyNumber myNumber, String s) {
		super();
		this.myNumber = myNumber;
		this.s = s;
	}

	@Override
	public void run() {
		myNumber.change(s);//s="b"
	}
}

package cn.it.sy;
/**
 * 该示例是为了演示非线程安全的情况
 * @author MR.W
 *
 */
public class Test {
	public static void main(String[] args) {
		//非线程安全:多个线程访问相同对象的同一实例变量
		MyNumber myNumber1 = new MyNumber();
//		MyNumber myNumber2 = new MyNumber();
		ThreadA a = new ThreadA(myNumber1, "a");
		a.setName("a");
		ThreadB b = new ThreadB(myNumber1, "b");
		b.setName("b");
		a.start();
		b.start();
	}
}

  1. 同步代码块
    1. 必须保证锁唯一
5.2 同步锁
5.3 volatile
6.线程优先级

线程默认优先级和父线程优先级保持一致

方法描述
setPriority(int i)设置线程优先级
getPriority()获取线程优先级
7.线程调度
方法描述
join()停止当前运行的线程,等待join的线程运行结束后再运行当前线程(插队)
yield()暂停当前线程,并重新调度线程,具有相同优先级或者更高优先级的线程优先执行
sleep(long l)线程休眠l毫秒,休眠结束后继续执行
8.线程间通信
方法描述
wait()线程挂起,等待其他线程唤醒,并释放锁
notify()随机唤醒某个调用wait()方法,处于阻塞状态的线程
notifyAll()唤醒所有因为调用wait()方法,处于阻塞状态的线程
8.1生产者消费者模式
9.线程面试题
  1. 请简述调用start()方法和run()方法的区别

    1. run()方法中定义线程执行的任务,start()方法则是用来启动线程
    2. 直接调用run方法jvm会将run()方法当做普通实例方法执行,而不是启动该线程
    3. 调用start()方法后,该线程进入就绪状态,当线程调度器为该线程分配时间片以后,该线程开始执行run方法
  2. 请简述创建线程的两种方式,及区别

    1. 创建线程可以继承Thread类,并重写run()方法
    2. 可以继承Runnable接口,并实现/重写run()方法
    3. 因为java中是单继承,通过继承Thread类创建线程后,该类则不能继承其他类,继承Runnable接口则可以继承其他类或者其他接口,有利于类的扩展。
    4. 继承Thread类可以直接调用start()方法启动线程,继承Runnable接口后则必须通过Thread的构造方法,传入改对象创建Thread对象再调用star()方法启动线程。
  3. 请简述sleep()方法和wait()的区别

    相同点:

    1. sleep和wait方法都可以使线程进入阻塞状态
    2. sleep和wait方法都会抛出InterruptedException

    不同点:

    1. sleep()方法在休眠结束后重新进入就绪状态,wait()方法会一直阻塞线程直到被唤醒
    2. sleep方法是Thread类的成员方法,wait()方法是Object类的成员方法
    3. sleep()方法不会释放,wait()方法会释放锁
  4. 定义两个线程操作同一个变量,一个线程对其加1,另一个线程对其减1,循环输出010101010101

package cn.it.java;

public class Print{
	int count = 0;
	public synchronized void printAdd(){
		if(count==1) {
			try {
				wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		count++;
		System.out.println(count);
		notify();
	}
	public synchronized void printReduce(){
		if(count==0) {
			try {
				wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		count--;
		System.out.println(count);
		notify();
	}
}

package cn.it.java;

public class Add extends Thread {
	private Print print;

	public Add(Print print) {
		super();
		this.print = print;
	}
	
	@Override
	public void run() {
		while (true) {
			print.printAdd();
		}
	}
}
package cn.it.java;

public class Reduce extends Thread {
	private Print print;

	public Reduce(Print print) {
		super();
		this.print = print;
	}
	
	@Override
	public void run() {
		while (true) {
			print.printReduce();
		}
	}
}

package cn.it.java;

public class Test {
	public static void main(String[] args) {
		Print p = new Print();
		Add add = new Add(p);
		Reduce reduce = new Reduce(p);
		add.start();
		reduce.start();
	}
}

  1. 定义三个线程,三个线程循环输入ABCABCABCABC
package cn.it.notify;

public class Print {
	
	boolean a = true;
	boolean b = false;
	boolean c = false;
	
	public synchronized void printA() {
		try {
			if(!a) {
				wait();
			}else if(a&&!b&&!c) {
				System.out.println("A");
				a = false;
				b = true;
				c = false;
				notifyAll();
			}
		} catch (InterruptedException e) {
			// TODO: handle exception
		}
	}
	public synchronized void printB() {
		try {
			if(!b) {
				wait();
			}else if(!a&&b&&!c) {
				System.out.println("B");
				a=false;
				b=false;
				c=true;
				notifyAll();
			}
		} catch (InterruptedException e) {
			// TODO: handle exception
		}
	}
	public synchronized void printC() {
		try {
			if(!c) {
				wait();
			}else if(!a&&!b&&c) {
				System.out.println("C");
				a=true;
				b=false;
				c=false;
				notifyAll();
			}
		} catch (InterruptedException e) {
			// TODO: handle exception
		}
	}
}
package cn.it.notify;

public class ThreadA extends Thread{
	private Print print;

	public ThreadA(Print print) {
		super();
		this.print = print;
	}
	
	@Override
	public void run() {
		// TODO Auto-generated method stub
		super.run();
		while(true) {
			print.printA();
		}
	}
}

package cn.it.notify;

public class ThreadB extends Thread{
	private Print print;

	public ThreadB(Print print) {
		super();
		this.print = print;
	}
	
	@Override
	public void run() {
		// TODO Auto-generated method stub
		super.run();
		while(true) {
			print.printB();
		}
	}
}

package cn.it.notify;

public class ThreadC extends Thread{
	private Print print;

	public ThreadC(Print print) {
		super();
		this.print = print;
	}
	
	@Override
	public void run() {
		// TODO Auto-generated method stub
		super.run();
		while (true) {
			print.printC();
		}
	}
}
package cn.it.notify;

public class Test {
	public static void main(String[] args) {
		Print print = new Print();
		
		ThreadA a = new ThreadA(print);
		
		ThreadB b = new ThreadB(print);
		
		ThreadC c = new ThreadC(print);
		
		a.start();
		b.start();
		c.start();
		
	}
}	

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值