1.理解解线程的概念及线程的生命周期。
2.掌握多线程的编程。
1.通过继承Thread类创建线程。
2.通过实现Runnable接口创建线程。
3.线程优先级操作。
4.用两个线程玩猜数字的游戏。
实验步骤:
1.通过继承Thread类创建一个实现睡眠(时间在1~5秒)功能的线程,显示它的睡眠时间及其线程名称。
源代码:
package homework.实验10_多线程;
public class sy10_1 {
public static void main(String[] args) {
Runner1 r = new Runner1();
r.start();
for (int i = 0; i < 3; i++) {
if(i==2){
try {
Runner1.sleep(1000); //此处是类名.sleep()
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Runner1.currentThread().getName()+"当前运行的线程名称: "+ i);
}
}
}
class Runner1 extends Thread{
public void run() {
for (int i = 0; i < 5; i++) {
if(i==4){
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println(Runner1.currentThread().getName()+"当前运行的线程名称: "+ i);
}
}
}
2.通过实现Runnable接口创建线程,要求产生三个线程对象,并分别设置三个线程的休眠时间:线程A休眠1秒,线程B休眠2秒,线程C休眠3秒。
源代码:
package homework.实验10_多线程;
public class sy10_2 {
public static void main(String[] args){
new Thread(new Sleep("线程A", 1000)).start();
new Thread(new Sleep("线程B", 2000)).start();
new Thread(new Sleep("线程C", 3000)).start();
}
}
class Sleep implements Runnable{
public long time;
public String name;
public Sleep(String name, long time){
this.name = name;
this.time = time;
}
@Override
public void run() {
// TODO Auto-generated method stub
try {
Thread.sleep(this.time);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(this.name+"休眠"+this.time+"毫秒");
}
}
3.创建三个线程,使得其中一个线程的优先级最高,一个线程的优先级最低,一个线程的优先级介于两者之间。要求显示各线程的名称及其优先级。
源代码:
package homework.实验10_多线程;
public class sy10_3 {
public static void main(String[] args){
Thread t1 = new Thread(new PriThread());
Thread t2 = new Thread(new PriThread());
Thread t3 = new Thread(new PriThread());
t1.setPriority(Thread.MAX_PRIORITY);
t2.setPriority(6);
t3.setPriority(Thread.MIN_PRIORITY);
t1.start();
t2.start();
t3.start();
}
}
class PriThread implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println(Thread.currentThread().getName()+"的优先级是:"
+Thread.currentThread().getPriority()+"");
}
}
4. 用两个线程玩猜数字的游戏:第一个线程负责随机给出1~100之间的一个整数,第二个线程负责猜出这个数。要求每当第二个线程给出自己的猜测后,第一个线程都会提示“猜小了”、“猜大了”或“猜对了”。
源代码:
package homework.实验10_多线程;
import java.util.*;
import java.util.Random;
public class sy10_4{
public static void main(String[] args) {
number num=new number("线程一");
num.start();
guess gue=new guess("线程二");
gue.start();
}
}
//给出整数的线程
class number extends Thread{
String name1;
private static int n;
number(String name){
name1=name;
}
public void run() {
//获取1~100的随机数
Random random=new Random();
n=random.nextInt(100);
System.out.println(name1+"给出的数字为:"+n);
}
//猜数字(静态方法,可通过类名调用)
public static String guessnum(int m) {
if(mn){
return "猜大了";
}else return "猜对了";
}
}
//猜数线程
class guess extends Thread{
String name2;
//最大值和最小值
private int min=0,max=100,nownum;
//比较结果
String Result;
guess(String name){
name2=name;
}
//获取比较结果
public String getGuess() {
return Result;
}
public void run() {
while(true) {
try{
Thread.sleep(2000);
}catch(InterruptedException e){
e.printStackTrace();
}
Random ran=new Random();
//当前猜的数字(最大值和最小值之间的数)
nownum=min+ran.nextInt(max-min);
//调用给出整数的线程 的猜数字方法guessnum,
Result=number.guessnum(nownum);
if(Result.equals("猜小了")) {
min=nownum;
System.out.println("线程二猜的数字是:"+nownum+"---猜小了");
}else if(Result.equals("猜大了")) {
max=nownum;
System.out.println("线程二猜的数字是:"+nownum+"---猜大了");
}else {
System.out.println("线程二猜的数字是:"+nownum+"---猜对了,结果是"+nownum);
System.exit(0);
}
}
}
}
运行结果截图:
实验小结
进程与线程
进程是程序的一次动态执行过程,它需要经历从代码加载,代码执行到执行完毕的一个完整的过程,这个过程也是进程本身从产生,发展到最终消亡的过程。多进程操作系统能同时达运行多个进程(程序),由于 CPU 具备分时机制,所以每个进程都能循环获得自己的CPU 时间片。由于 CPU 执行速度非常快,使得所有程序好像是在同时运行一样。
多线程是实现并发机制的一种有效手段。进程和线程一样,都是实现并发的一个基本单位。线程是比进程更小的执行单位,线程是进程的基础之上进行进一步的划分。所谓多线程是指一个进程在执行过程中可以产生多个更小的程序单元,这些更小的单元称为线程,这些线程可以同时存在,同时运行,一个进程可能包含多个同时执行的线程。
Java中线程实现的方式
在 Java 中实现多线程有两种手段,一种是继承 Thread 类,另一种就是实现 Runnable 接口。
实现Runnable接口例子:
class MyThread implements Runnable{ // 实现Runnable接口,作为线程的实现类
private String name ; // 表示线程的名称
public MyThread(String name){
this.name = name ; // 通过构造方法配置name属性
}
public void run(){ // 覆写run()方法,作为线程 的操作主体
for(int i=0;i<10;i++){
System.out.println(name + "运行,i = " + i) ;
}
}
};
public class RunnableDemo01{
public static void main(String args[]){
MyThread mt1 = new MyThread("线程A ") ; // 实例化对象
MyThread mt2 = new MyThread("线程B ") ; // 实例化对象
Thread t1 = new Thread(mt1) ; // 实例化Thread类对象
Thread t2 = new Thread(mt2) ; // 实例化Thread类对象
t1.start() ; // 启动多线程
t2.start() ; // 启动多线程
}
};
实现Thread接口
class MyThread extends Thread{ // 继承Thread类,作为线程的实现类
private String name ; // 表示线程的名称
public MyThread(String name){
this.name = name ; // 通过构造方法配置name属性
}
public void run(){ // 覆写run()方法,作为线程 的操作主体
for(int i=0;i<10;i++){
System.out.println(name + "运行,i = " + i) ;
}
}
};
public class ThreadDemo02{
public static void main(String args[]){
MyThread mt1 = new MyThread("线程A ") ; // 实例化对象
MyThread mt2 = new MyThread("线程B ") ; // 实例化对象
mt1.start() ; // 调用线程主体
mt2.start() ; // 调用线程主体
}
};
从程序可以看出,现在的两个线程对象是交错运行的,哪个线程对象抢到了 CPU 资源,哪个线程就可以运行,所以程序每次的运行结果肯定是不一样的,在线程启动虽然调用的是 start() 方法,但实际上调用的却是 run() 方法定义的主体。
线程的状态变化
要想实现多线程,必须在主线程中创建新的线程对象。任何线程一般具有5种状态,即创建,就绪,运行,阻塞,终止。
创建:Thread thread=new Thread()
就绪:调用该线程的 start() 方法就可以启动线程。
运行:当就绪状态被调用并获得处理器资源时,线程就进入了运行状态。此时,自动调用该线程对象的 run() 方法。run() 方法定义该线程的操作和功能。
阻塞:调用sleep(),suspend(),wait() 等方法,线程都将进入阻塞状态
终止:线程调用 stop() 方法时或 run() 方法执行结束后,即处于死亡状态。处于死亡状态的线程不具有继续运行的能力。
在 Java 的线程操作中,所有的线程在运行前都会保持在就绪状态,那么此时,哪个线程的优先级高,哪个线程就有可能会先被执行。