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.线程生命周期

新生:线程类new出对象,此时内存中仅仅是为对象分配内存空间,为成员变量赋初始值。

就绪:调用线程start()方法后线程进入就绪状态,此时线程并不是立即执行,而是等待线程调度器分配时间片,当该线程得到资源后,调用线程run()方法

运行:线程run()方法运行时。

阻塞:当线程因为某些原因不能继续运行,并放弃所占用的处理器资源时,就进入阻塞状态,阻塞状态不能直接进入运行状态,而是当阻塞结束是,重新进入就绪状态,重新等待线程调度器分配资源。当出现如下情况时,线程进入阻塞。

线程调用sleep()方法时,当sleep()休眠时间结束时,线程进入就绪状态

线程调用阻塞式IO方法,在该方法返回之前,线程被阻塞

线程试图获得一个同步监视器,但是该监视器正在被其他线程持有

线程在等待某个notify()

死亡:run()方法执行完成,或者线程抛出异常

5.线程同步

5.1synchronized

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

同步方法

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();

}

}

同步代码块

必须保证锁唯一

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.线程面试题

请简述调用start()方法和run()方法的区别

run()方法中定义线程执行的任务,start()方法则是用来启动线程

直接调用run方法jvm会将run()方法当做普通实例方法执行,而不是启动该线程

调用start()方法后,该线程进入就绪状态,当线程调度器为该线程分配时间片以后,该线程开始执行run方法

请简述创建线程的两种方式,及区别

创建线程可以继承Thread类,并重写run()方法

可以继承Runnable接口,并实现/重写run()方法

因为java中是单继承,通过继承Thread类创建线程后,该类则不能继承其他类,继承Runnable接口则可以继承其他类或者其他接口,有利于类的扩展。

继承Thread类可以直接调用start()方法启动线程,继承Runnable接口后则必须通过Thread的构造方法,传入改对象创建Thread对象再调用star()方法启动线程。

请简述sleep()方法和wait()的区别

相同点:

不同点:

sleep()方法在休眠结束后重新进入就绪状态,wait()方法会一直阻塞线程直到被唤醒

sleep方法是Thread类的成员方法,wait()方法是Object类的成员方法

sleep()方法不会释放,wait()方法会释放锁

sleep和wait方法都可以使线程进入阻塞状态

sleep和wait方法都会抛出InterruptedException

定义两个线程操作同一个变量,一个线程对其加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();

}

}

定义三个线程,三个线程循环输入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();

}

}

你可能感兴趣的:(Java多线程学习及面试题)