【Java基础】· 多线程习题详解

写在前面


        Hello大家好, 我是【麟-小白】,一位软件工程专业的学生,喜好计算机知识。希望大家能够一起学习进步呀!本人是一名在读大学生,专业水平有限,如发现错误不足之处,请多多指正!谢谢大家!!!

        如果小哥哥小姐姐们对我的文章感兴趣,请不要吝啬你们的小手,多多点赞加关注呀!❤❤❤ 爱你们!!!


目录

写在前面

java中有几种方法可以实现一个线程(jdk5.0之前)?用什么关键字修饰同步方法? stop()和suspend()方法为何不推荐使用?

sleep() 和 wait() 有什么区别?

同步和异步有何异同,在什么情况下分别使用他们?举例说明。

启动一个线程是用run()还是start()?

当一个线程进入一个对象的一个synchronized方法后,其它线程是否可进入此对象的其它方法?

请说出你所知道的线程同步的方法。

多线程有几种实现方法,都是什么?同步有几种实现方法,都是什么?

线程的基本概念、线程的基本状态以及状态之间的关系

简述synchronized和java.util.concurrent.locks.Lock的异同 ?

案例:三个线程间的通讯

一、判断题

1.C 和 Java 都是多线程语言。(×)

2.如果线程死亡,它便不能运行。(√)

3.在 Java 中,高优先级的可运行线程会抢占低优先级线程。(√)

4.程序开发者必须创建一个线程去管理内存的分配。(×)

5.一个线程在调用它的 start 方法,之前,该线程将一直处于出生期。(√)

6.当调用一个正在进行线程的 stop()方法时,该线程便会进入休眠状态。(×)

7.如果线程的 run 方法执行结束或抛出一个不能捕获的例外,线程便进入等待状态。(×)

8.一个线程可以调用 yield 方法使其他线程有机会运行。(√)

二、选择题

1.Java 语言中提供了一个▁D▁线程,自动回收动态分配的内存。

2.当▁A▁方法终止时,能使线程进入死亡状态。

3.用▁B▁方法可以改变线程的优先级。

4.线程通过▁C▁方法可以使具有相同优先级线程获得处理器。

5.线程通过▁D▁方法可以休眠一段时间,然后恢复运行。

6.▁B▁方法使对象等待队列的第一个线程进入就绪状态。

7.方法 resume( )负责重新开始▁D▁线程的执行。

8.▁BCD▁方法可以用来暂时停止当前线程的运行。

Java为什么要引入线程机制,线程、程序、进程之间的关系是怎样的。

Runnable接口包括哪些抽象方法?Thread类有哪些主要域和方法?

创建线程有哪两种方式(jdk5.0之前)?试写出每种的具体的流程。比较两种创建方式的不同,哪个更优。

创建多线程题目

在{1}添加什么代码,可以保证如下代码输出100

利用多线程设计一个程序,同时输出 50 以内的奇数和偶数,以及当前运行的线程名。

建立线程有几种方法?

模拟一个人生产50个玩具,每200毫秒生产一个,当生产到第20个时加入每秒吃1个馒头,共吃完3个后在接着生产的多线程。

在多线程中,为什么要引入同步机制?

wait()、notify()、notifyAll()的作用分别是什么?

结语


【多线程知识精讲】

一文带你深入理解【Java基础】· 多线程(下)

一文带你深入理解【Java基础】· 多线程(上)


java中有几种方法可以实现一个线程(jdk5.0之前)?用什么关键字修饰同步方法? stop()和suspend()方法为何不推荐使用?

答:有两种实现方法,分别是继承Thread类与实现Runnable接口。

用synchronized关键字修饰同步方法,反对使用stop(),是因为它不安全。它会解除由线程获取的所有锁定,而且如果对象处于一种不连贯状态,那么其他线程能在那种状态下检查和修改它们。结果很难检查出真正的问题所在。

suspend()方法容易发生死锁。调用suspend()的时候,目标线程会停下来,但却仍然持有在这之前获得的锁定。此时,其他任何线程都不能访问锁定的资源,除非被"挂起"的线程恢复运行。对任何线程来说,如果它们想恢复目标线程,同时又试图使用任何一个锁定的资源,就会造成死锁。所以不应该使用suspend(),而应在自己的Thread类中置入一个标志,

指出线程应该活动还是挂起。若标志指出线程应该挂起,便用wait()命其进入等待状态。若标志指出线程应当恢复,则用一个notify()重新启动线程。


sleep() 和 wait() 有什么区别?

答:sleep是线程类(Thread)的方法,导致此线程暂停执行指定时间,给执行机会给其他线程,但是监控状态依然保持,到时后会自动恢复。调用sleep不会释放对象锁。

wait是Object类的方法,对此对象调用wait方法导致本线程放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象发出notify方法(或notifyAll)后本线程才进入对象锁定池准备获得对象锁进入运行状态。


同步和异步有何异同,在什么情况下分别使用他们?举例说明。

答:如果数据将在线程间共享。例如正在写的数据以后可能被另一个线程读到,或者正在读的数据可能已经被另一个线程写过了,那么这些数据就是共享数据,必须进行同步存取。

当应用程序在对象上调用了一个需要花费很长时间来执行的方法,并且不希望让程序等待方法的返回时,就应该使用异步编程,在很多情况下采用异步途径往往更有效率。


启动一个线程是用run()还是start()?

答:启动一个线程是调用start()方法,使线程所代表的虚拟处理机处于可运行状态,这意味着它可以由JVM调度并执行。这并不意味着线程就会立即运行。run()方法就是正常的对象调用方法的执行,并不是使用分线程来执行的。


当一个线程进入一个对象的一个synchronized方法后,其它线程是否可进入此对象的其它方法?

答:不能,一个对象的一个synchronized方法只能由一个线程访问。


请说出你所知道的线程同步的方法。

答:wait():使一个线程处于等待状态,并且释放所持有的对象的lock。

sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要捕捉InterruptedException异常。

notify():唤醒一个处于等待状态的线程,注意的是在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由JVM确定唤醒哪个线程,而且不是按优先级。

notityAll():唤醒所有处入等待状态的线程,注意并不是给所有唤醒线程一个对象的锁,而是让它们竞争。

多线程有几种实现方法,都是什么?同步有几种实现方法,都是什么?

答:多线程有两种实现方法,分别是继承Thread类与实现Runnable接口(jdk5.0之前)

同步的实现方面有两种,分别是synchronized,wait与notify


线程的基本概念、线程的基本状态以及状态之间的关系

答:线程指在程序执行过程中,能够执行程序代码的一个执行单位,每个程序至少都有一个线程,也就是程序本身。

Java中的线程有五种状态分别是:创建、就绪、运行、阻塞、结束


简述synchronized和java.util.concurrent.locks.Lock的异同 ?

答:主要相同点:Lock能完成synchronized所实现的所有功能

主要不同点:Lock有比synchronized更精确的线程语义和更好的性能。synchronized会自动释放锁,而Lock一定要求程序员手工释放,并且必须在finally从句中释放。


案例:三个线程间的通讯

public class Demo01 {
	public static void main(String[] args) {
		//三个线程间的通讯
		MyTask task = new MyTask();
		new Thread(){
			public void run() {
				while(true){
					try {
						task.task1();
					} catch (InterruptedException e1) {
						e1.printStackTrace();
					}
					try {
						Thread.sleep(10);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			};
		}.start();
		new Thread(){
			public void run() {
				while(true){
					try {
						task.task2();
					} catch (InterruptedException e1) {
						e1.printStackTrace();
					}
					try {
						Thread.sleep(10);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			};
		}.start();
		new Thread(){
			public void run() {
				while(true){
					try {
						task.task3();
					} catch (InterruptedException e1) {
						e1.printStackTrace();
					}
					try {
						Thread.sleep(10);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			};
		}.start();
	}
}

class MyTask{
	
	//标识 1:可以执行任务1,2:可以执行任务2, 3:可以执行任务3 
	int flag = 1;
	
	public synchronized void task1() throws InterruptedException{
		if(flag != 1){
			this.wait();//当前线程等待
			//this.wait(timeout);
		}
		
		System.out.println("1.银行信用卡自动还款任务...");
		flag = 2;
		//this.notify();//唤醒随机线程
		this.notifyAll();//唤醒所有等待线程
		
	}
	
	public synchronized void task2() throws InterruptedException{
		
		if(flag != 2){
			this.wait();//线程等待
		}
		
		System.out.println("2.银行储蓄卡自动结算利息任务...");
		flag = 3;
		//this.notify();//唤醒其它线程
		this.notifyAll();
	}
	
	public synchronized void task3() throws InterruptedException{
			if(flag != 3){
				this.wait();//线程等待
			}
			
			System.out.println("3.银行短信提醒任务...");
			flag = 1;
			//this.notify();//唤醒其它线程
			this.notifyAll();
	}
}


一、判断题

1.C 和 Java 都是多线程语言。(×)

2.如果线程死亡,它便不能运行。(√)

3.在 Java 中,高优先级的可运行线程会抢占低优先级线程。(√)

4.程序开发者必须创建一个线程去管理内存的分配。(×)

5.一个线程在调用它的 start 方法,之前,该线程将一直处于出生期。(√)

6.当调用一个正在进行线程的 stop()方法时,该线程便会进入休眠状态。(×)

7.如果线程的 run 方法执行结束或抛出一个不能捕获的例外,线程便进入等待状态。(×)

8.一个线程可以调用 yield 方法使其他线程有机会运行。(√)

【答案】

1.难度:容易

答案:错误

知识点:C 是单线程语言。

2.难度:容易

答案:正确

知识点:线程死亡就意味着它不能运行。

3.难度:适中

答案:正确

知识点:线程优先级的使用。

4.难度:适中

答案:错误

知识点:Java 提供了一个系统线程来管理内存的分配。

5.难度:容易

答案:正确

知识点:出生期的概念。

6.难度:适中

答案:错误

知识点:应该是 sleep 方法。

7.难度:适中

答案:错误

知识点:如果线程的 run 方法执行结束或抛出一个不能捕获的例外,线程便进入死亡状态。

8.难度:适中

答案:正确

知识点:yield 方法总是让高优先级的就绪线程先运行。


二、选择题

1.Java 语言中提供了一个▁D▁线程,自动回收动态分配的内存。

A 异步

B 消费者

C 守护

D 垃圾收集

2.当▁A▁方法终止时,能使线程进入死亡状态。

A run

B setPrority

C yield

D sleep

3.用▁B▁方法可以改变线程的优先级。

A run

B setPrority

C yield

D sleep

4.线程通过▁C▁方法可以使具有相同优先级线程获得处理器。

A run

B setPrority

C yield

D sleep

5.线程通过▁D▁方法可以休眠一段时间,然后恢复运行。

A run

B setPrority

C yield

D sleep

6.▁B▁方法使对象等待队列的第一个线程进入就绪状

A run

B notify

C yield

D sleep

7.方法 resume( )负责重新开始▁D▁线程的执行。

A 被 stop( )方法停止

B 被 sleep( )方法停止

C 被 wait( )方法停止

D 被 suspend( )方法停止

8.▁BCD▁方法可以用来暂时停止当前线程的运行。

A stop( )

B sleep( )

C wait( )

D suspend()

【答案】

1.难度:容易

答案:D

知识点:垃圾线程的使用。

2.难度:容易

答案:A

知识点:run 方法的使用。

3.难度:容易

答案:B

知识点:setPrority 方法的使用。

4.难度:容易

答案:C

知识点:yield 方法的使用。

5.难度:容易

答案:D

知识点:sleep 方法的使用。

6.难度:容易

答案:B

知识点:notify 方法的使用。

7.难度:适中

答案:D

知识点:一个线程被用 suspend( )方法,将该线程挂起。并通过调用 resume( )方法来重新开始线程的执行。

但是该方法容易导致死锁,应尽量避免使用。

8.难度:适中

答案:BCD

知识点:当调用 stop( )方法后,当前的线程不能重新开始运行。


Java为什么要引入线程机制,线程、程序、进程之间的关系是怎样的。

答:线程可以彼此独立的执行,它是一种实现并发机制的有效手段,可以同时使用多个线程来完成不同的任务,并且一般用户在使用多线程时并不考虑底层处理的细节。

程序是一段静态的代码,是软件执行的蓝本。进程是程序的一次动态执行过程,即是处于运行过程中的程序。

线程是比进程更小的程序执行单位,一个进程可以启动多个线程同时运行,不同线程之间可以共享相同的内存区域和数据。多线程程序是运行时间后嗣可能出现在一个进程之内的、有一个以上线程同时运行的情况的程序。


Runnable接口包括哪些抽象方法?Thread类有哪些主要域和方法?

答:Runnable接口中仅有run()抽象方法。

Thread类主要域有:MAX_PRIORITY,MIN_PRIORITY,NORM_PRIORITY。

主要方法有start(),run(),sleep(),currentThread(),setPriority(),getPriority(),join()等。


创建线程有哪两种方式(jdk5.0之前)?试写出每种的具体的流程。比较两种创建方式的不同,哪个更优。

1—继承Thread类

1)  定义类继承Thread类。

2)  覆盖Thread类中的run方法。

3)  创建Thread子类对象,即创建了线程对象。

4)  调用线程对象start方法:启动线程,调用run方法。

2—实现Runnable接口

1)定义类,实现Runnable接口。

2)覆盖Runnable接口中的run方法。

3)通过Thread类建立线程对象。

4)将Runnable接口的子类对象作为实际参数传递给Thread类的构造方法中。

5)调用Thread类的start方法:开启线程,调用Runnable子类接口的run方法。

【区别】

继承Thread: 线程代码存放Thread子类run方法中。

实现Runnable:线程代码存在接口的子类的run方法中。

【实现方法的好处】

1)避免了单继承的局限性

2)多个线程可以共享同一个接口子类的对象,非常适合多个相同线程来处理同一份资源。


创建多线程题目

编写一个继承Thread类的方式实现多线程的程序。该类MyThread有两个属性,一个字符串WhoAmI代表线程名,一个整数delay代表该线程随机要休眠的时间。构造有参的构造器,线程执行时,显示线程名和要休眠时间。

另外,定义一个测试类TestThread,创建三个线程对象以展示执行情况。

class MyThread extends Thread {
	private String whoAmI;
	private int delay;

	public MyThread(String s, int d) {
		whoAmI = s;
		delay = d;
	}

	public void run() {
		try {
			sleep(delay);
		} catch (InterruptedException ie) {
		}
		System.out.println("Hello!I am" + whoAmI + ",I slept" + delay + "milliseconds");
	}
}

public class TestThread {
	public static void main(String[] args) {
		MyThread t1 = new MyThread("Thread-1", (int) (Math.random() * 100));
		MyThread t2 = new MyThread("Thread-2", (int) (Math.random() * 100));
		MyThread t3 = new MyThread("Thread-3", (int) (Math.random() * 100));
		t1.start();
		t2.start();
		t3.start();
	}
}


在{1}添加什么代码,可以保证如下代码输出100

提示:t.wait()  或  t.jion()  或 t.yield() 或  t.interrupt()?

public class Test {
	public static void main(String[] args) {
		MyThread m = new MyThread();
		Thread t = new Thread(m);
		t.start();
		
		        {1}              
		
		int j = m.i;
		System.out.println(j);
	}
}
class MyThread implements Runnable{
	int i;
	public void run(){
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		i=100;
	}
}

答案:t.join()


利用多线程设计一个程序,同时输出 50 以内的奇数和偶数,以及当前运行的线程名。

public class ThreadPrint extends Thread {
	int k = 1;

	public void run() {
		int i = k;
		while (i < 50) {
			System.out.println(Thread.currentThread().getName() + "-----" + i);
			i += 2;
		}
		System.out.println(Thread.currentThread().getName() + " end!");
	}

	public static void main(String[] args) {
		ThreadPrint t1 = new ThreadPrint();
		ThreadPrint t2 = new ThreadPrint();
		t1.k = 1;
		t2.k = 2;
		t1.start();
		t2.start();
	}
}


建立线程有几种方法?

四种。继承Thread类、实现Runnable接口、实现Callable接口、使用线程池创建。(仅以当前水平)


模拟一个人生产50个玩具,每200毫秒生产一个,当生产到第20个时加入每秒吃1个馒头,共吃完3个后在接着生产的多线程。

/**
 @author LinXiaobai
 @create 2022-11-13 17:38
 */
public class Test1 {
    public static void main(String[] args) {
        Person p = new Person();
        Producer pro = new Producer(p);
        EatBread eat = new EatBread(p);

        new Thread(pro).start();
        new Thread(eat).start();

    }
}

class Person {
    boolean flag;
    //吃馒头
    public synchronized void eat() {
        if (flag) {
            for (int i = 1; i <= 3; i++) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("吃了第" + i + "个馒头");
            }
            this.notify();
        }
    }

    //生产玩具
    public synchronized void product() {
        for (int i = 1; i <= 50; i++) {
            if (i == 21) {
                flag = true;
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("生产了一个玩具,目前个数为:" + i);
        }
    }
}

class Producer implements Runnable {
    private Person p;

    public Producer(Person p) {
        this.p = p;
    }

    @Override
    public void run() {
        p.product();
    }

}

class EatBread implements Runnable {
    private Person p;

    public EatBread(Person p) {
        this.p = p;
    }

    @Override
    public void run() {
        p.eat();
    }

}


在多线程中,为什么要引入同步机制?

同步机制可以实现线程之间的通信,同步机制保证共享资源只能被一个线程所持有,

避免了多线程执行时数据的不安全问题.


wait()notify()notifyAll()的作用分别是什么?

wait()、notify()和notifyAll()都是Object类中的final方法,被所有的类继承,且不允许重写的方法。

当一个线程使用的同步方法中用到某个变量,而此变量又需要其它线程修改后才能符合本线程的需要,那么可以在同步方法中使用wait()方法。使用wait()方法可以中断方法的执行,使本线程等待,暂时让出CPU 的使用权,并允许其它线程使用这个同步方法。其它线程如果在使用这个同步方法时不需要等待,那么它使用完这个同步方法的同时,应当用notifyAll()方法通知所有的由于使用这个同步方法而处于等待的线程结束等待。(如果使用notify()方法则只通知处于等待中的某一个线程结束等待)


结语


本人会持续更新文章的哦!希望大家一键三连,你们的鼓励就是作者不断更新的动力

  • 4
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

麟-小白

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值