Top

JAVA SE02 Unit04

  1. 创建两个线程,分别输出1~100
  2. 编写一个线程改变窗体的颜色V1
  3. 测试currentThread方法
  4. 测试getName方法和getId方法
  5. 测试守护线程
  6. 编写一个线程改变窗体的颜色V2
  7. 测试join方法

1 创建两个线程,分别输出1~100

1.1 问题

使用Thread创建两个线程,分别输出1~100。

1.2 步骤

实现此案例需要按照如下步骤进行。

步骤一:新建TestThread类及MyThread类

首先,新建类TestThread;然后,在该类所在的文件中新建类MyThread,MyThread类继承自Thread类,代码如下所示:

/**
 * 测试线程
 */
public class TestThread {
	/**
	 * 测试多线程并发运行
	 */
	public static void main(String[] args) {
	}
}
/**
 * 线程
 */
class MyThread extends Thread{
}

步骤二:实现输出1到100

在MyThead类中覆盖run方法,在该方法中实现输出1到100,代码如下所示:

/**
 * 测试线程
 */
public class TestThread {
	/**
	 * 测试多线程并发运行
	 */
	public static void main(String[] args) {
	}
}
/**
 * 线程
 */
class MyThread extends Thread{
#cold_bold	public void run(){
#cold_bold		for(int i=1;i<=100;i++){
#cold_bold			System.out.println(i);
#cold_bold		}
#cold_bold	}
}

步骤三:创建并启动线程

在TestThread类的main方法中,创建两个线程t1和t2,然后使用线程t1、t2的start方法启动线程,代码如下所示:

/**
 * 测试线程
 */
public class TestThread {
	/**
	 * 测试多线程并发运行
	 */
#cold_bold	public static void main(String[] args) {
#cold_bold		Thread t1 = new MyThread();	
#cold_bold		Thread t2 = new MyThread();	
#cold_bold		t1.start();
#cold_bold		t2.start();
#cold_bold	}
}
/**
 * 线程
 */
class MyThread extends Thread{
	public void run(){
		for(int i=1;i<=100;i++){
			System.out.println(i);
		}
	}
}

运行TestThread类,控制台会输出两次1到100。

1.3 完整代码

本案例的完整代码如下所示:

/**
 * 测试线程
 */
public class TestThread {
	/**
	 * 测试多线程并发运行
	 */
	public static void main(String[] args) {
		Thread t1 = new MyThread();	
		Thread t2 = new MyThread();	

		t1.start();
		t2.start();
	}
}
/**
 * 线程
 */
class MyThread extends Thread{
	public void run(){
		for(int i=1;i<=100;i++){
			System.out.println(i);
		}
	}
}

2 编写一个线程改变窗体的颜色V1

2.1 问题

编写一个线程改变窗体的颜色,详细要求如下:

1)使用Runnable创建线程,该线程实现窗口的颜色在黑色和白色之间不断的切换。

2)使用内部类创建线程的方式,实现窗口的颜色在黑色和白色之间不断的切换。

2.2 步骤

实现此案例需要按照如下步骤进行。

步骤一:新建类TestRunnable

创建TestRunnable类,该类继承自JFrame类,并实现Runnable接口,代码如下所示:

import javax.swing.JFrame;
/**
 * 测试Runnable
 */
public class TestRunnable extends JFrame implements Runnable{
	public static void main(String[] args) {
	}
}

步骤二:覆盖Runnable接口的run方法,实现窗体颜色切换

在TestRunnable类中,覆盖Runnable接口的run方法。在该方法中,首先创建JPanel类的对象panel,并将其放在窗体上;然后,使用while(true)循环,在循环中,切换panel的颜色从而达到窗体颜色变化,代码如下所示:

import java.awt.Color;
import javax.swing.JFrame;
import javax.swing.JPanel;
/**
 * 测试Runnable
 */
public class TestRunnable extends JFrame implements Runnable{
#cold_bold	@Override
#cold_bold	public void run() {
#cold_bold		int i = 0;
#cold_bold		JPanel panel = new JPanel();
#cold_bold		panel.setSize(300, 300);
#cold_bold		this.setContentPane(panel);
#cold_bold		while(true){
#cold_bold			i = i==0?1:0;
#cold_bold			if(i==0){
#cold_bold				panel.setBackground(Color.BLACK);
#cold_bold			}else{
#cold_bold				panel.setBackground(Color.WHITE);
#cold_bold			}
#cold_bold		}
	}
	public static void main(String[] args) {
	}
}

步骤三:显示窗体、启动线程

在TestRunnable类的main方法中,首先设置窗体显示,然后启动线程,代码如下所示:

import java.awt.Color;
import javax.swing.JFrame;
import javax.swing.JPanel;
/**
 * 测试Runnable
 */
public class TestRunnable extends JFrame implements Runnable{
	@Override
	public void run() {
		int i = 0;
		JPanel panel = new JPanel();
		panel.setSize(300, 300);
		this.setContentPane(panel);
		while(true){
			i = i==0?1:0;
			if(i==0){
				panel.setBackground(Color.BLACK);
			}else{
				panel.setBackground(Color.WHITE);
			}
		}
	}
	public static void main(String[] args) {
#cold_bold		TestRunnable r = new TestRunnable();
#cold_bold		r.setSize(300, 300);
#cold_bold		r.setVisible(true);
#cold_bold		r.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
#cold_bold		Thread t = new Thread(r);
#cold_bold		t.start();
	}
}

运行TestRunnable类会显示窗体,窗体在黑色和白色之间不断切换。

步骤四:使用内部类的方式创建线程

使用内部类创建线程的方式,实现窗口的颜色在黑色和白色之间不断的切换,代码如下所示:

import java.awt.Color;
import javax.swing.JFrame;
import javax.swing.JPanel;

/**
 * 使用匿名内部类形式创建线程
 * @author Xiloer
 *
 */
public class TestInnerThread {
	public static void main(String[] args) {
		JFrame frame = new JFrame();
		frame.setSize(300,300);
		final JPanel panel = new JPanel();
		panel.setSize(300,300);
		frame.setContentPane(panel);
		frame.setVisible(true);
		Thread t = new Thread(){
			public void run(){
				int i =0;
				while(true){
					i = i==0?1:0;
					if(i==0){
						panel.setBackground(Color.BLACK);
					}else{
						panel.setBackground(Color.WHITE);
					}
				}
			}
		};
		t.start();
	}
}

2.3 完整代码

本案例中,类TestRunnable的完整代码如下所示:

import java.awt.Color;
import javax.swing.JFrame;
import javax.swing.JPanel;
/**
 * 测试Runnable
 */
public class TestRunnable extends JFrame implements Runnable{
	@Override
	public void run() {
		int i = 0;
		JPanel panel = new JPanel();
		panel.setSize(300, 300);
		this.setContentPane(panel);
		while(true){
			i = i==0?1:0;
			if(i==0){
				panel.setBackground(Color.BLACK);
			}else{
				panel.setBackground(Color.WHITE);
			}
		}
	}
	public static void main(String[] args) {
		TestRunnable r = new TestRunnable();
		r.setSize(300, 300);
		r.setVisible(true);
		r.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		Thread t = new Thread(r);
		t.start();
	}
}

类TestInnerThread的完整代码如下所示:

import java.awt.Color;
import javax.swing.JFrame;
import javax.swing.JPanel;

/**
 * 使用匿名内部类形式创建线程
 * @author Xiloer
 *
 */
public class TestInnerThread {
	public static void main(String[] args) {
		JFrame frame = new JFrame();
		frame.setSize(300,300);
		final JPanel panel = new JPanel();
		panel.setSize(300,300);
		frame.setContentPane(panel);
		frame.setVisible(true);
		Thread t = new Thread(){
			public void run(){
				int i =0;
				while(true){
					i = i==0?1:0;
					if(i==0){
						panel.setBackground(Color.BLACK);
					}else{
						panel.setBackground(Color.WHITE);
					}
				}
			}
		};
		t.start();
	}
}

3 测试currentThread方法

3.1 问题

测试currentThread方法,详细要求如下:

1)新建类TestCurrentThread,在该类中创建方法testCurrent实现输出当前线程。

2)在TestCurrentThread类的main方法中,输出当前线程并调用testCurrent查看当前线程。

3)在main方法中,使用内部类创建线程t,该线程中实现输出当前线程并调用testCurrent查看当前线程。

4)启动线程t。

3.2 步骤

实现此案例需要按照如下步骤进行。

步骤一:新建TestCurrentThread类,添加testCurrent方法

新建类TestCurrentThread,在该类中创建方法testCurrent,在该方法中使用Thread类的静态方法currentThread获取当前线程并输出当前线程,代码如下所示:

/**
 * 测试当前线程
 */
public class TestCurrentThread {
	public static void main(String[] args) {
	}
	/**
	 * 测试不同线程调用该方法时,获取这个线程
	 */
	public static void testCurrent(){
		System.out.println("运行testCurrent方法的线程是:"+Thread.currentThread());
	}
}

步骤二:在main方法中获取当前线程

在TestCurrentThread类的main方法中,输出当前线程并调用testCurrent查看当前线程,代码如下所示:

/**
 * 测试当前线程
 */
public class TestCurrentThread {
	public static void main(String[] args) {
#cold_bold		System.out.println("运行main方法的线程:"+Thread.currentThread());
#cold_bold		testCurrent();
	}
	/**
	 * 测试不同线程调用该方法时,获取这个线程
	 */
	public static void testCurrent(){
		System.out.println("运行testCurrent方法的线程是:"+Thread.currentThread());
	}
}

运行TestCurrentThread方法,控制台输出结果如下:

运行main方法的线程:Thread[main,5,main]
运行testCurrent方法的线程是:Thread[main,5,main]

输出结果中的“Thread[main,5,main]”表示当前线程的名字为main、优先级为5、当前线程的组线程为main。

步骤三:在内部类中查看当前线程

在main方法中,首先,使用内部类创建线程t,该线程中实现输出当前线程并调用testCurrent查看当前线程;然后启动线程t,代码如下所示:

/**
 * 测试当前线程
 */
public class TestCurrentThread {
	public static void main(String[] args) {
		System.out.println("运行main方法的线程:"+Thread.currentThread());
		testCurrent();
#cold_bold		Thread t = new Thread(){
#cold_bold			@Override
#cold_bold			public void run() {
#cold_bold				System.out.println("线程t:"+Thread.currentThread());
#cold_bold				testCurrent();
#cold_bold			}
#cold_bold		};
#cold_bold		t.start();
	}
	/**
	 * 测试不同线程调用该方法时,获取这个线程
	 */
	public static void testCurrent(){
		System.out.println("运行testCurrent方法的线程是:"+Thread.currentThread());
	}
}

运行TestCurrentThread类,控制台的输出结果如下:

运行main方法的线程:Thread[main,5,main]
运行testCurrent方法的线程是:Thread[main,5,main]
#cold_bold线程t:Thread[Thread-0,5,main]
#cold_bold运行testCurrent方法的线程是:Thread[Thread-0,5,main]

输出结果中的“Thread[Thread-0,5,main]”表示当前线程的名字为Thread-0、优先级为5、当前线程的组线程为main。

3.3 完整代码

本案例的完整代码如下所示:

/**
 * 测试当前线程
 */
public class TestCurrentThread {
	public static void main(String[] args) {
		System.out.println("运行main方法的线程:"+Thread.currentThread());
		testCurrent();
		Thread t = new Thread(){
			@Override
			public void run() {
				System.out.println("线程t:"+Thread.currentThread());
				testCurrent();
			}
		};
		t.start();
	}
	/**
	 * 测试不同线程调用该方法时,获取这个线程
	 */
	public static void testCurrent(){
		System.out.println("运行testCurrent方法的线程是:"
										+Thread.currentThread());
	}
}

4 测试getName方法和getId方法

4.1 问题

测试Thread类的getName方法和getID方法,详细要求如下:

1)创建两个线程,输出默认的线程名字和默认的ID。

2)创建一个线程,设置线程的名字并输出线程名字和默认的ID。

4.2 步骤

实现此案例需要按照如下步骤进行。

步骤一:获取默认的线程名字和ID

首先,新建类TestThreadNameAndId,在该类的main方法中,创建两个线程t0、t1;接着分别使用Thread类的getName方法和getId方法获取线程的名字和ID,代码如下所示:

/**
 * 获取线程名字及ID
 */
public class TestThreadNameAndId {
	/**
	 * 测试线程的getName方法以及getId方法
	 */
	public static void main(String[] args) {
		Thread t = new Thread();
		System.out.println(t.getName());
		System.out.println(t.getId());
		
		Thread t1 = new Thread();
		System.out.println(t1.getName());
		System.out.println(t1.getId());
	}
}

运行TestThreadNameAndId类,控制台的输出结果如下:

Thread-0
9
Thread-1
10

从输出结果可以看出,默认的线程名字为“Thread-+数字”的形式;ID为从数字9开始的,这是因为,9之前的数字被虚拟机的线程占用掉了。

步骤二:为线程添加自定义的名字

在构造Thread类的对象时,可以通过Thread(String)这个构造方法给线程自定义名字,代码如下所示:

/**
 * 获取线程名字及ID
 */
public class TestThreadNameAndId {
	/**
	 * 测试线程的getName方法以及getId方法
	 */
public static void main(String[] args) {
		Thread t = new Thread();
		System.out.println(t.getName());
		System.out.println(t.getId());
		
		Thread t1 = new Thread();
		System.out.println(t1.getName());
		System.out.println(t1.getId());

#cold_bold		Thread t2 = new Thread("自定义名字的Thread");
#cold_bold		System.out.println(t2.getName());
#cold_bold		System.out.println(t2.getId());
	}
}

运行TestThreadNameAndId类,控制台的输出结果如下:

Thread-0
9
Thread-1
10
#cold_bold自定义名字的Thread
#cold_bold11

从输出结果可以看出,当通过构造方法设置自定义名字后,使用Thread类的getName方法获取名字时得到的则是自定义的名字。

4.3 完整代码

本案例的完整代码如下所示:

/**
 * 获取线程名字及ID
 */
public class TestThreadNameAndId {
	/**
	 * 测试线程的getName方法以及getId方法
	 */
public static void main(String[] args) {
		Thread t = new Thread();
		System.out.println(t.getName());
		System.out.println(t.getId());
		
		Thread t1 = new Thread();
		System.out.println(t1.getName());
		System.out.println(t1.getId());
		
		Thread t2 = new Thread("自定义名字的Thread");
		System.out.println(t2.getName());
		System.out.println(t2.getId());
	}
}

5 测试守护线程

5.1 问题

测试守护线程,详细要求如下:

1)使用内部类创建线程的方式创建线程d,该线程实现每隔0.1秒输出字符串“后台线程”。

2)设置线程d为守护线程并启动该线程。

3)使main线程阻塞5秒,然后输出字符串"main线程结束了"。

5.2 步骤

实现此案例需要按照如下步骤进行。

步骤一:创建线程,实现每隔0.1秒输出字符串“后台线程”

首先新建类TestDaemonThread;然后在该类的main方法中,使用内部类创建线程的方式创建线程d;最后,线程d实现每隔0.1秒输出字符串“后台线程”,代码如下所示:

public class TestDaemonThread {
	public static void main(String[] args) {
		Thread d = new Thread(){
			public void run() {
				while(true){
					System.out.println("后台线程");
					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
					}
				}
			}
		};
	}
}

步骤二:设置d线程为后台线程

在main方法中,首先,设置d线程为后台线程并启动该线程;然后,使用Thread类的sleep方法使main线程阻塞5秒;最后,输出字符串“main线程结束了”,代码如下所示:

public class TestDaemonThread {
	public static void main(String[] args) {
		Thread d = new Thread(){
			public void run() {
				while(true){
					System.out.println("后台线程");
					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
					}
				}
			}
		};
#cold_bold		d.setDaemon(true);
#cold_bold		d.start();		
#cold_bold		try {
#cold_bold			Thread.sleep(5000);
#cold_bold		} catch (InterruptedException e) {
#cold_bold		}
#cold_bold		//进程中所有前台线程结束后,后台线程强制结束
#cold_bold		System.out.println("main线程结束了");
	}
}

运行TestDaemonThread类,控制台会不断输出字符串“后台线程”,直到输出字符串“main线程结束了”为止。这是因为,d线程被设置为守护线程,守护线程的特点是,当进程中只剩下守护线程时,所有守护线程强制终止。

5.3 完整代码

本案例的完整代码如下所示:

public class TestDaemonThread {
	public static void main(String[] args) {
		Thread d = new Thread(){
			public void run() {
				while(true){
					System.out.println("后台线程");
					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
					}
				}
			}
		};
		d.setDaemon(true);
		d.start();		
		try {
			Thread.sleep(5000);
		} catch (InterruptedException e) {
		}
		//进程中所有前台线程结束后,后台线程强制结束
		System.out.println("main线程结束了");
	}
}

6 编写一个线程改变窗体的颜色V2

6.1 问题

在案例“编写一个线程改变窗体的颜色V1”基础上实现当前案例,即,在使用内部类创建线程的方式,实现窗口的颜色在黑色和白色之间不断的切换的基础上,实现每隔一秒窗体的颜色在黑色和白色之间切换。

6.2 步骤

实现此案例需要按照如下步骤进行。

步骤一:新建TestSleep类

新建TestSleep类,使该类中的代码与TestInnerThread类中的代码保持一致,代码如下所示:

/**
 * 测试sleep方法
 */
public class TestSleep {
	public static void main(String[] args) {
		JFrame frame = new JFrame();
		frame.setSize(300,300);
		final JPanel panel = new JPanel();
		panel.setSize(300,300);
		frame.setContentPane(panel);
		frame.setVisible(true);
		Thread t = new Thread(){
			public void run(){
				int i =0;
				while(true){
					i = i==0?1:0;
					if(i==0){
						panel.setBackground(Color.BLACK);
					}else{
						panel.setBackground(Color.WHITE);
					}
				}
			}
		};
		t.start();
	}
}

步骤二:实现颜色切换

使用Thread类的sleep方法实现每隔一秒窗体的颜色在黑色和白色之间切换,代码如下所示:

/**
 * 测试sleep方法
 */
public class TestSleep {
	public static void main(String[] args) {
		JFrame frame = new JFrame();
		frame.setSize(300,300);
		final JPanel panel = new JPanel();
		panel.setSize(300,300);
		frame.setContentPane(panel);
		frame.setVisible(true);
		Thread t = new Thread(){
			public void run(){
				int i =0;
				while(true){
					i = i==0?1:0;
					if(i==0){
						panel.setBackground(Color.BLACK);
					}else{
						panel.setBackground(Color.WHITE);
					}
#cold_bold					try {
#cold_bold						Thread.sleep(1000);
#cold_bold					} catch (InterruptedException e) {
#cold_bold						e.printStackTrace();
#cold_bold					}
				}
			}
		};
		t.start();
	}
}

运行TestSleep类,会显示窗体,窗体上的颜色每隔一秒在黑色和白色之间切换。

6.3 完整代码

本案例中,类TestSleep的完整代码如下所示:

/**
 * 测试sleep方法
 */
public class TestSleep {
	public static void main(String[] args) {
		JFrame frame = new JFrame();
		frame.setSize(300,300);
		final JPanel panel = new JPanel();
		panel.setSize(300,300);
		frame.setContentPane(panel);
		frame.setVisible(true);
		Thread t = new Thread(){
			public void run(){
				int i =0;
				while(true){
					i = i==0?1:0;
					if(i==0){
						panel.setBackground(Color.BLACK);
					}else{
						panel.setBackground(Color.WHITE);
					}
					try {
						Thread.sleep(1000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		};
		t.start();
	}
}

7 测试join方法

7.1 问题

使用两个线程模拟图片下载的过程,详细要求如下:

1) 创建线程t1,该线程模拟实现图片下载的过程,即在该线程中实现输出字符串“t1:正在下载图片:”+下载的百分数,例如:“t1:正在下载图片:30%”;到100%之后,显示“t1:图片下载完成”。

2)创建线程t2,在该线程中,首先输出“t2:等待图片下载完毕”;然后将t1线程作为t2线程的子线程;最后,输出"t2:显示图片"。

3)启动线程t1,t2。

4)要求,一定是线程t1执行完毕之后,才会执行线程 t2 中的显示图片。即显示了“t1:图片下载完成”之后,才会显示“t2:显示图片”。

7.2 步骤

实现此案例需要按照如下步骤进行。

步骤一:创建线程t1

新建类TestJoin,该类的main方法中创建线程t1,该线程模拟实现图片下载的过程,即在该线程中实现输出字符串“t1:正在下载图片:”+下载的百分数,例如:“t1:已下载图片:30%”,代码如下所示:

public class TestJoin {
	public static void main(String[] args) {
		final Thread t1 = new Thread(){
			public void run(){
				for(int i=0;i<=10;i++){
					System.out.println("t1:正在下载图片:"+i*10+"%");
					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				System.out.println("t1:图片下载完成");
			}
		};
	}
}

步骤二:创建线程t2

在main方法中,创建线程t2,在该线程中,首先输出“t2:等待图片下载完毕”;然后将t1线程作为t2线程的子线程;最后,输出"t2:显示图片",代码如下所示:

public class TestJoin {
	public static void main(String[] args) {
		final Thread t1 = new Thread(){
			public void run(){
				for(int i=0;i<=10;i++){
					System.out.println("t1:正在下载图片:"+i*10+"%");
					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				System.out.println("t1:图片下载完成");
			}
		};
#cold_bold		Thread t2 = new Thread(){
#cold_bold			public void run(){
#cold_bold				System.out.println("t2:等待图片下载完毕");
#cold_bold				try {
#cold_bold					t1.join();
#cold_bold				} catch (InterruptedException e) {
#cold_bold					e.printStackTrace();
#cold_bold				}
#cold_bold				System.out.println("t2:显示图片");
#cold_bold			}
#cold_bold		};
	}
}

步骤三:启动线程

启动线程t1,t2,代码如下所示:

public class TestJoin {
	public static void main(String[] args) {
		final Thread t1 = new Thread(){
			public void run(){
				for(int i=0;i<=10;i++){
					System.out.println("t1:正在下载图片:"+i*10+"%");
					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				System.out.println("t1:图片下载完成");
			}
		};
		Thread t2 = new Thread(){
			public void run(){
				System.out.println("t2:等待图片下载完毕");
				try {
					t1.join();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println("t2:显示图片");
			}
		};
#cold_bold		t1.start();
#cold_bold		t2.start();
	}
}

步骤四:测试

运行TestJoin类,控制台会输出“t2:等待图片下载完毕”,也会输出“t1:正在下载图片:0%”,以及“t1:正在下载图片:10%“等信息。最后,直到输出“t1:图片下载完成”后,才会输出“t2:显示图片”。

这是因为使用了join方法,该方法在此用于等待t1线程执行结束,再执行t2线程。

7.3 完整代码

本案例中,类TestJoin的完整代码如下所示:

public class TestJoin {
	public static void main(String[] args) {
		final Thread t1 = new Thread(){
			public void run(){
				for(int i=0;i<=10;i++){
					System.out.println("t1:正在下载图片:"+i*10+"%");
					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				System.out.println("t1:图片下载完成");
			}
		};
		Thread t2 = new Thread(){
			public void run(){
				System.out.println("t2:等待图片下载完毕");
				try {
					t1.join();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println("t2:显示图片");
			}
		};
		t1.start();
		t2.start();
	}
}