多线程
一、概念题
- 简述程序、进程和线程之间的关系,什么是多线程程序?
-
程序:指令和数据的有序集合,其本身没有任何运行含义。是一个静态的概念。
-
进程:执行程序的一次执行过程,它是一个动态的概念。是系统资源分配的单位
-
线程:通常一个进程中可以包含若干个线程,线程是cpu调度和执行的单位,是独立的执行路径。eg:main()称之为主线程,是系统的入口,用于执行整个程序
多线程程序:
很多多线程是模拟出来的,真正的多线程是指有多个cpu,即多核(如服务器),如果是模拟出来的多线程,即在一个cpu的情况下,在同一个时间点,cpu只能执行一个代码,但是切换的很快。
-
线程有哪五个基本状态?他们之间如何转化?简述线程的生命周期。
-
新建状态:
使用 new 关键字和 Thread 类或其子类建立一个线程对象后,该线程对象就处于新建状态。它将保持这个状态直到程序 start() 这个线程。 -
就绪状态:
当线程对象调用了start()方法之后,该线程就进入就绪状态。就绪状态的线程处于就绪队列中,要等待JVM里线程调度器的调度。 -
运行状态:
如果就绪状态的线程获取 CPU 资源,就可以执行run(),此时线程便处于运行状态。处于运行状态的线程最为复杂,它可以变为阻塞状态、就绪状态和死亡状态。 -
阻塞状态:
如果一个线程执行了sleep(睡眠)、suspend(挂起)等方法,失去所占用资源之后,该线程就从运行状态进入阻塞状态。在睡眠时间已到或获得设备资源后可以重新进入就绪状态。可以分为三种:
- 等待阻塞:运行状态中的线程执行 wait() 方法,使线程进入到等待阻塞状态。
- 同步阻塞:线程在获取 synchronized 同步锁失败(因为同步锁被其他线程占用)。
- 其他阻塞:通过调用线程的 sleep() 或 join() 发出了 I/O 请求时,线程就会进入到阻塞状态。当sleep() 状态超时,join() 等待线程终止或超时,或者 I/O 处理完毕,线程重新转入就绪状态。
-
死亡状态:
一个运行状态的线程完成任务或者其他终止条件发生时,该线程就切换到终止状态。
-
-
Runable接口中包括哪些抽象方法?Thread类中有哪写主要的成员变量和方法?
Runnable接口中仅有run()抽象方法。
Thread类主要域有:MAX_PRIORITY,MIN_PRIORITY,NORM_PRIORITY。
主要方法有start(),run(),sleep(),currentThread(),setPriority(),getPriority(),join()等。 -
start()方法和run()方法的区别,sleep()和wait()的异同
start()方法和run()方法的区别:
只有调用了start()方法,才会表现出多线程的特性,使不同线程的run()方法里面的代码交替执行。
如果只是调用run()方法,必须等待一个线程的run()方法里面的代码全部执行完毕之后,另外一个线程才可以执行其run()方法里面 的代码。
sleep()和wait()的异同:
sleep方法和wait方法都可以用来放弃CPU一定的时间
不同点在于如果线程持有某个对象的监视器,sleep方法不会放弃这个对象的监视器,wait方法会放弃这个对象的监视器
-
如何在java程序中实现多线程?简述使用Thread字类和实现Runnable接口两种方法的异同。
因为实现接口的方式比继承类的方式更灵活,也能减少程序之间的耦合度,符合设计模式6大原则的核心——>面向接口编程。
-
了解lambada表达式(了解即可)
package com.Thread; public class TestLambda1 { //3.静态内部类 static class Like2 implements ILike{ @Override public void lambda() { System.out.println("i like lambda2"); } } public static void main(String[] args) { ILike like = new Like(); like.lambda(); like = new Like2(); like.lambda(); //4.局部内部类 class Like3 implements ILike{ @Override public void lambda() { System.out.println("i like lambda3"); } } like = new Like3(); like.lambda(); //5.匿名内部类,没有类的名称,必须借助接口或者父类 like = new ILike() { @Override public void lambda() { System.out.println("i like lambda4"); } }; like.lambda(); //6.用lambda简化 like = ()->{ System.out.println("i like lambda5"); }; like.lambda(); /* 简化1.参数类型 like = (a)->{ System.out.println("i like lambda5"); }; 简化2.简化括号 like = a->{ System.out.println("i like lambda5"); }; 简化3.去掉花括号(代码只有一行的情况下) like = a->System.out.println("i like lambda5"); */ } } //1.定义一个函数式接口(就是只有一个方法的类) interface ILike{ void lambda(); } //2.实现类 class Like implements ILike{ @Override public void lambda() { System.out.println("i like lambda1"); } }
二、编程题
-
使用Thread.sleep()编写一个倒计时10秒的java程序,输出10,9,8…1;
public static void main(String[] args) { try { tenDown(); } catch (InterruptedException e) { e.printStackTrace(); } } public static void tenDown() throws InterruptedException { int num = 10; while (true){ Thread.sleep(1000); System.out.println(num--); if (num<=0){ break; } } }
-
三个黄牛同时抢200张票,打印出哪个黄牛买了第几张票
public class demo02 { public static void main(String[] args) { BuyTicket station = new BuyTicket(); new Thread(station,"黄牛A").start(); new Thread(station,"黄牛B").start(); new Thread(station,"黄牛C").start(); } } class BuyTicket implements Runnable{ //票 private int ticketNums = 200; boolean flag = true;//外部停止方法 @Override public void run() { //买票 while (flag){ try { //模拟延迟 Thread.sleep(100); buy(); } catch (InterruptedException e) { e.printStackTrace(); } } } private synchronized void buy(){ //判断是否有票 if (ticketNums<=0){ flag = false; return; } //买票显示 System.out.println(Thread.currentThread().getName()+"拿到第"+ticketNums--+"张票"); } }
-
编写一个程序,启动三个线程,三个线程的ID分别是A,B,C;每个线程将自己的ID值在屏幕上打印5遍,打印顺序是ABCABC…重复三遍
public class demo03 { private static Lock lock = new ReentrantLock(); private static int state = 0;//通过state的值来判断是否打印 private static int count =15; static class ThreadA extends Thread { @Override public void run() { for (int i = 0; i < count;) { try { lock.lock(); while (state %3 == 0) { System.out.print("A"); state++; i++; } } finally { lock.unlock(); } } } } static class ThreadB extends Thread { @Override public void run() { for (int i = 0; i < count;) { try { lock.lock(); while (state %3 == 1) { System.out.print("B"); state++; i++; } } finally { lock.unlock(); } } } } static class ThreadC extends Thread { @Override public void run() { for (int i = 0; i < count;) { try { lock.lock(); while (state %3 == 2) { System.out.print("C"); state++; i++; if (state==15){ System.out.println('\n'); state=0; } } } finally { lock.unlock(); } } } } public static void main(String[] args) { new ThreadA().start(); new ThreadB().start(); new ThreadC().start(); } }
三、挑战题
1.制作一个给定时间的倒计时器
package java0018;
import java.util.Scanner;
public class demo04 {
public static void main(String[] args) {
try {
timeDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void timeDown() throws InterruptedException {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入倒计时时间:");
int time = scanner.nextInt();
while (true){
int hh = time /60 /60;
int mm = (time-hh*3600) / 60;
int ss = (time-hh*3600-mm*60) ;
Thread.sleep(1000);
time--;
System.out.println(hh+"时"+mm+"分"+ss+"秒");
scanner.close();
if (time<=0){
break;
}
}
}
}
2.编写一个java程序,同时用冒泡排序和选择排序实现对一个整型数组的排序,试着输出一下他们的运行时间,如果能实现更多的排序也可以尝试一下
提示
给出了一些代码,请补充完整。
可以跟着参考代码敲理解,主要是对排序和多线程的综合应用,对多线程知识要求不高。
当然如果可以独立写出来可不看提示代码独立完成。
package java0018;
//Sort类
class Sort implements Runnable{
int [] data;
public Sort(int [] data){
super();
this.data = data;
}
@Override
public void run() {
long start = System.nanoTime();
sort();
long end = System.nanoTime();
System.out.println(Thread.currentThread().getName()+"执行花费了"+(end-start)+"ns");
}
public void sort(){
throw new RuntimeException("在子类重写此方法");
}
}
//BubbleSort类 冒泡排序
class BubbleSort extends Sort{
public BubbleSort(int[] data) {
super(data);
}
@Override
public void sort(){
try {
sort(data);
}catch (Exception e){
e.printStackTrace();
}
}
void sort(int[] data)throws Exception{
/*
冒泡排序的代码
*/
int temp;
for (int i = 0; i < data.length-1; i++) {
for (int j = i+1; j < data.length; j++) {
if (data[j]>data[i]){
temp = data[i];
data[i] = data[j];
data[j] = temp;
}
}
}
}
}
//选择排序SelectionSort类 选择排序
class SelectionSort extends Sort{
public SelectionSort(int[] data) {
super(data);
}
@Override
public void sort(){
try {
sort(data);
}catch (Exception e){
e.printStackTrace();
}
}
void sort(int[] data)throws Exception{
/*
选择排序的代码
*/
int temp;
int k;
for (int i = 0; i < data.length-1; i++) {
k=i;
for (int j = i+1; j < data.length; j++) {
if (data[k] < data[j]){
k = j;
}
}
if (k != i){
temp = data[i];
data[i] = data[k];
data[k] = temp;
}
}
}
}
public class MainTest {
public static void main(String[] args) {
final int count = 10;
int[] data = createData(count);
//=====?????==========复制数组 请补充 思考一下为什么要复制=======??????==========
int[] data1 = new int[count];
for (int i = 0; i < data.length; i++) {
data1[i] = data[i];
}
//创建冒泡排序线程
Sort s1 = new BubbleSort(data1);
//创造选择排序线程
Sort s2 = new SelectionSort(data1);
//启动线程
new Thread(s1,"冒泡排序:").start();
new Thread(s2,"选择排序:").start();
}
/*
创造数组方法,参数为数组大小;
*/
private static int [] createData(int count){
int [] data = new int[count];
for (int i = 0 ; i < data.length;i++){
data[i] = (int)(Math.random()*count);
}
return data;
}
}
BubbleSort(data1);
//创造选择排序线程
Sort s2 = new SelectionSort(data1);
//启动线程
new Thread(s1,"冒泡排序:").start();
new Thread(s2,"选择排序:").start();
}
/*
创造数组方法,参数为数组大小;
*/
private static int [] createData(int count){
int [] data = new int[count];
for (int i = 0 ; i < data.length;i++){
data[i] = (int)(Math.random()*count);
}
return data;
}
}