模拟新年倒计时,每隔1秒输出一个数字,依次输出10,9,8…1,最后输出:新年快乐!
public class Exercise1 {
public static void main(String[] args) {
for (int i = 10; i>=0; i--) {
System.out.println(i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("新年快乐!");
}
}
案例:在子线程中输出1-100之间的偶数,主线程输出1-100之间的奇数。
效果如下:
public class Exercise2 {
public static void main(String[] args) {
new Thread("子线程"){
public void run(){
for (int i = 0; i <= 100; i+=2) {
System.out.println(getName() + "-->" + i);
}
}
}.start();
for (int i = 1; i <= 100; i+=2) {
System.out.println("main主线程 -->" + i);
}
}
}
自定义线程类ChatThread:问是否结束(输入Y/y结束),如果输入的不是y,继续问是否结束,直到输入y才结束。
打印[1,10],每隔10毫秒打印一个数字,现在当主线程打印完5之后,就让自定义线程类加塞,直到自定义线程类结束,主线程再继续。
public class ChatThread extends Thread{
public void run(){
Scanner input = new Scanner(System.in);
while(true){
System.out.print("是否结束(Y、N):");
String answer = input.nextLine();
if(!"".equals(answer) && Character.toUpperCase(answer.charAt(0))=='Y'){
break;
}
}
input.close();
}
}
public class Exercise3 {
public static void main(String[] args) {
for (int i = 1; i <= 10; i++) {
System.out.println("main:" + i);
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
//当main打印到5之后,需要等join进来的线程停止后才会继续了。
if(i==5){
ChatThread t = new ChatThread();
t.start();
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
声明一个PrintEvenThread线程类,继承Thread类,重写run方法,实现打印[1,100]之间的偶数,要求每隔1毫秒打印1个偶数。
声明一个PrintOddThread线程类,继承Thread类,重写run方法,实现打印[1,100]之间的奇数。
在main线程中:
(1)创建两个线程对象,并启动两个线程
(2)当打印奇数的线程结束了,让偶数的线程也停下来,就算偶数线程没有全部打印完[1,100]之间的偶数。
public class PrintEvenThread extends Thread{
private boolean flag = true;
@Override
public void run() {
for (int i = 2; i <= 100 && flag; i += 2) {
System.out.println("偶数线程:" + i);
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void setFlag(boolean flag) {
this.flag = flag;
}
}
public class PrintOddThread extends Thread {
@Override
public void run() {
for (int i = 1; i <= 100; i += 2) {
System.out.println("奇数线程:" + i);
}
}
}
public class Exercise4 {
public static void main(String[] args) {
PrintEvenThread pe = new PrintEvenThread();
PrintOddThread po = new PrintOddThread();
pe.start();
po.start();
try {
po.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
pe.setFlag(false);
}
}
案例:编写龟兔赛跑多线程程序,设赛跑长度为30米
兔子的速度是10米每秒,兔子每跑完10米休眠的时间10秒
乌龟的速度是1米每秒,乌龟每跑完10米的休眠时间是1秒
要求:要等兔子和乌龟的线程结束,主线程(裁判)才能公布最后的结果。
//提示:System.currentTimeMillis()方法可以返回当前时间的毫秒值(long类型)
long start = System.currentTimeMillis();
//中间代码
long end = System.currentTimeMillis();
System.out.println("中间代码运行耗时:" + (end - start) +"毫秒")
public class Racer extends Thread{
private long meterTime;//跑1米的时间
private long restTime;//跑完10米休息时间
private long time; //记录总用时
//有参构造
public Racer(String name, long meterTime, long restTime) {
super(name);
this.meterTime = meterTime;
this.restTime = restTime;
}
public void run(){
long start = System.currentTimeMillis(); //获取时间值,现在距离1970-1-1 0.0.0 0的毫秒值
for (int i=1; i<=30; i++){//i单位是米
try {
Thread.sleep(meterTime);
System.out.println(getName() + "已经跑了" + i + "米");
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
if(i==10 || i==20){
System.out.println(getName() +"正在休息....");
Thread.sleep(restTime);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(getName() + "到达终点.");
long end = System.currentTimeMillis(); //获取时间值,现在距离1970-1-1 0.0.0 0的毫秒值
time = end - start;
}
public long getTime() {
return time;
}
}
public class Exercise5 {
public static void main(String[] args) {
//裁判线程执行(main线程)
Racer r = new Racer("兔子",100,10000);
Racer t = new Racer("乌龟",1000,1000);
r.start();
t.start();
//让r和t线程都结束了,才能继续main
try {
r.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("兔子用时:" + r.getTime());
System.out.println("乌龟用时:" + t.getTime());
if(r.getTime() < t.getTime()){
System.out.println("兔子赢");
}else if(r.getTime() > t.getTime()){
System.out.println("乌龟赢");
}else{
System.out.println("平局");
}
}
}
案例:编写龟兔赛跑多线程程序,设赛跑长度为30米
兔子的速度是10米每秒,兔子每跑完10米休眠的时间10秒
乌龟的速度是1米每秒,乌龟每跑完10米的休眠时间是1秒
要求:只要兔子和乌龟中有人到达终点,就宣布比赛结束,没到达终点的选手也要停下来。
public class Sporter extends Thread {
private long meterTime;//跑每米用时
private long restTime;//跑完10米休息的时间
private long time;//从跑到停的时间
private int distance;//当前运动员一共跑了几米
private final int MAX_DISTANCE = 30;
private static boolean flag = true;//true表示跑
//有参构造
public Sporter(String name, long meterTime, long restTime) {
super(name);
this.meterTime = meterTime;
this.restTime = restTime;
}
public void run() {
long start = System.currentTimeMillis(); //获取时间值,现在距离1970-1-1 0.0.0 0的毫秒值
while(distance < MAX_DISTANCE && flag){
try {
Thread.sleep(meterTime);
distance++;
System.out.println(getName() + "已经跑了" + distance + "米");
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
if (distance == 10 || distance == 20) {
System.out.println(getName() + "正在休息....");
Thread.sleep(restTime);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if(distance == MAX_DISTANCE){
flag = false;
System.out.println(getName() + "到达终点.");
}
long end = System.currentTimeMillis(); //获取时间值,现在距离1970-1-1 0.0.0 0的毫秒值
time = end - start;
System.out.println(getName() + "停止跑");
}
public long getTime() {
return time;
}
public static boolean isFlag() {
return flag;
}
public int getDistance() {
return distance;
}
}
public class Exercise6 {
public static void main(String[] args) {
Sporter s1 = new Sporter("兔子",100,10000);
Sporter s2 = new Sporter("乌龟",1000,1000);
s1.start();
s2.start();
try {
s1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
s2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
//宣布结果
if(s1.getDistance() > s2.getDistance()){
System.out.println("兔子赢");
}else if(s1.getDistance() <s2.getDistance()){
System.out.println("乌龟赢");
}else{
//距离一样
//System.out.println("平局");
//如果要再严格一点
if(s1.getTime() < s2.getTime()){
System.out.println("兔子赢");
}else if(s1.getTime() > s2.getTime()){
System.out.println("乌龟赢");
}else{
System.out.println("平局");
}
}
}
}
案例:请按要求编写多线程应用程序,模拟多个人通过一个山洞:
? 1、这个山洞每次只能通过一个人,每个人通过山洞的时间为5秒;
? 2、随机生成10个人,同时准备过此山洞
? 3、定义一个变量用于记录通过隧道的人数
? 4、显示每次通过山洞人的姓名,和通过顺序;
案例运行效果如下:
开发提示:
(1)定义一个隧道类,例如Tunnel,实现Runnable接口:
定义一个int类型的变量crossNum,用来记录通过隧道的人数;
重写Runnable的run方法,调用通过隧道的方法cross()
定义通过隧道的方法void cross(),模拟每个人通过隧道需要5秒钟
(2)定义测试类
在main方法中创建一个隧道类对象;
在main方法中,循环创建10个子线程对象,通过构造方法把隧道对象和线程名(作为人的姓名)传递进去,并开启子线程;
public class Tunnel implements Runnable {
// 1.1 定义一个变量,用来记录通过隧道的人数
private int crossNum = 0;
/*
* 1.2 重写Runnable的run方法
*/
@Override
public void run() {
// 1.4 调用通过隧道的方法
cross();
}
/*
* 1.3 定义一个同步方法,模拟每个人通过隧道需要5秒钟
*/
public synchronized void cross() {
//1.3.1 打印 xx开始通过隧道...
System.out.println(Thread.currentThread().getName() + "开始通过隧道...");
// 1.3.2 子线程睡眠5秒钟,模拟每个人通过隧道需要5秒钟
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 1.3.3 改变通过的人次
crossNum++;
// 1.3.4 打印线程名称及其通过隧道的顺序,模拟人通过隧道及其顺序
System.out.println(Thread.currentThread().getName() + "已经通过隧道,TA是第" + crossNum + "通过的!");
}
}
public class Exercise7 {
public static void main(String[] args) {
// 2.1 在main方法中创建一个隧道类对象
Tunnel tul = new Tunnel();
// 2.2 在main方法中,循环创建10个子线程对象,通过构造方法把隧道对象和// 线程名(作为人的姓名)传递进去,并开启子线程
for (int i = 1; i <= 10; i++) {
Thread t = new Thread(tul, "p" + i);
t.start();
}
}
}
案例:创建和启动2个子线程,一个打印100以内的奇数,一个打印100以内的偶数,
(1)要求每个线程要么不打印,要么就连续打印5个数,每个数打印间隔50毫秒
(2)但两个线程不要求交替打印。
效果如下:
//方式1
public class Exercise8 {
public static void main(String[] args) {
new PrintEven().start();
new PrintOdd().start();
}
}
class PrintEven extends Thread {
private int num = 2;
public void run() {
while (num <= 100) {
synchronized (Thread.class) {
for (int i = 1; i <= 5; i++) {
System.out.println("偶数线程,第" + i + "个:" + num);
num += 2;
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
class PrintOdd extends Thread {
private int num = 1;
public void run() {
while (num <= 100) {
synchronized (Thread.class) {
for (int i = 1; i <= 5; i++) {
System.out.println("奇数线程,第" + i + "个:" + num);
num += 2;
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
//方式2
/*
(1)声明一个资源类,例如PrintNumber,
- 包含一个int类型的变量even,初始化为2
- 包含一个int类型的变量odd,初始化为1
- 包含void printEven()方法,循环输出5个偶数
- 包含void printOdd()方法,循环输出5个奇数
(2)在测试类中
- 创建资源类PrintNumber的对象
- 启动一个偶数线程,调用PrintNumber的对象printEven()方法
- 启动一个奇数数线程,调用printOdd的对象printEven()方法
*/
class PrintNumber {
private int even = 2;
private int odd = 1;
public synchronized void printEven(){
for (int i = 1; i <=5 ; i++,even += 2) {
System.out.println(Thread.currentThread().getName()+"本轮打印的第" + i + "个数字:" + even);
}
}
public synchronized void printOdd(){
for (int i = 1; i <=5 ; i++,odd+=2) {
System.out.println(Thread.currentThread().getName()+"本轮打印的第" + i + "个数字:" + odd);
}
}
}
public class Exercise8 {
public static void main(String[] args) {
PrintNumber p = new PrintNumber();
new Thread("偶数线程"){
@Override
public void run(){
while(true){
p.printEven();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
new Thread("奇数线程"){
@Override
public void run(){
while(true){
p.printOdd();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}
}
案例需求:
要求两个线程,同时打印字母,每个线程都能连续打印3个字母。两个线程交替打印,一个线程打印字母的小写形式,一个线程打印字母的大写形式,但是字母是连续的。当字母循环到z之后,回到a。
案例运行效果如下:
开发提示:
(1)声明一个资源类,例如:PrintLetter
(2)在测试类中
public class PrintLetter {
private char letter = 'a';
public synchronized void printLower() {
for (int i = 1; i <= 3; i++) {
System.out.println(Thread.currentThread().getName() + "->" + letter);
letter++;
if (letter > 'z') {
letter = 'a';
}
}
this.notify();
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized void printUpper() {
for (int i = 1; i <= 3; i++) {
System.out.println(Thread.currentThread().getName() + "->" + (char) (letter - 32));
letter++;
if (letter > 'z') {
letter = 'a';
}
}
this.notify();
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class Exercise9 {
public static void main(String[] args) {
// 创建资源对象
PrintLetter p = new PrintLetter();
// 创建两个线程打印
new Thread("小写字母") {
public void run() {
while (true) {
p.printLower();
try {
Thread.sleep(1000);// 控制节奏
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
new Thread("大写字母") {
public void run() {
while (true) {
p.printUpper();
try {
Thread.sleep(1000);// 控制节奏
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}
}
案例:创建和启动2个子线程,一个打印奇数,一个打印偶数,
(1)要求实现交替打印。
(2)每个数打印间隔1秒
效果如下:
//方式1
public class Exercise10 {
public static void main(String[] args) {
new PrintNumber().start();
new PrintNumber().start();
}
}
class PrintNumber extends Thread{
private static int num;
public void run(){
while(true){
synchronized (PrintNumber.class) {
try {
PrintNumber.class.notify();
Thread.sleep(1000);
System.out.println(getName() + ":" + ++num);
PrintNumber.class.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
//方式2
/*
(1)编写一个资源类,例如:Number类,
- 包含1个int类型的num,用来记录线程要打印的数字,初始值为1。
- 包含1个boolean类型的odd,用来标记是奇数线程打印还是偶数线程打印,true表示奇数线程打印,false表示偶数线程打印。初始化为true。
- 包含void printOddNum()方法,判断odd为true,就打印num,之后修改odd为false,然后唤醒偶数线程,之后自己wait。
- 包含void printEvenNum()方法,判断odd为false,就打印num,之后修改odd为true,然后唤醒奇数线程,之后自己wait。
(2)在测试类中
- 创建Number类对象
- 创建一个奇数线程,并启动,重写run方法,循环调用Number类对象的printOddNum()方法。
- 创建一个偶数线程,并启动,重写run方法,循环调用Number类对象的printEvenNum()方法。
*/
class Number {
private int num = 1;
private boolean odd = true;
public synchronized void printOddNum(){
if(odd){
System.out.println(Thread.currentThread().getName() + ":" + num++);
}
odd = false;
this.notify();
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized void printEvenNum(){
if(!odd){
System.out.println(Thread.currentThread().getName() + ":" + num++);
}
odd = true;
this.notify();
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public int getNum() {
return num;
}
}
public class Exercise10 {
public static void main(String[] args) {
Number number = new Number();
new Thread(){
public void run(){
while(true){
number.printOddNum();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
new Thread(){
public void run(){
while(true){
number.printEvenNum();
}
}
}.start();
}
}
案例:
? 1、创建一个银行账户类,
? (1)属性:账号,余额
? (2)get/set方法
? (3)toString():返回:账户:xxx,余额:xxx
? 2、创建一个丈夫类
? 负责往里存钱,每次存款[0,10000)以内不等
? 3、创建一个妻子类
? 负责取钱,每次取款[0,10000)以内不等,如果余额不足,要等丈夫存够了才能取
public class Exercise11 {
public static void main(String[] args) {
Account a = new Account("1122",0);
new Wife(a).start();
new Husband(a).start();
}
}
class Account{
private String id;
private double balance;
public Account(String id, double balance) {
super();
this.id = id;
this.balance = balance;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public double getBalance() {
return balance;
}
public void setBalance(double balance) {
this.balance = balance;
}
@Override
public String toString() {
return "账户:" + id + ",余额:" + balance ;
}
}
class Wife extends Thread{
private Account account;
public Wife(Account account) {
super();
this.account = account;
}
public void run(){
while(true){
synchronized (Thread.class) {
double money = Math.random() * 10000;
while(money > account.getBalance()){
System.out.println("本次妻子想取钱:" + money +",但是余额不足,等待...");
try {
Thread.class.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("妻子开始取钱,目前账户状态:" + account);
System.out.println("本次妻子取钱:" + money);
account.setBalance(account.getBalance() - money);
System.out.println("妻子取钱结束,目前账户状态:" + account);
System.out.println();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
class Husband extends Thread{
private Account account;
public Husband(Account account) {
super();
this.account = account;
}
public void run(){
while(true){
synchronized (Thread.class) {
double money = Math.random() * 10000;
System.out.println("丈夫开始存钱,目前账户状态:" + account);
System.out.println("本次丈夫存钱:" + money);
account.setBalance(account.getBalance() + money);
System.out.println("丈夫开始结束,目前账户状态:" + account);
System.out.println();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Thread.class.notify();
}
}
}
}
(1)创建一个银行账户类Account
(2)创建一个丈夫线程类Husband
(3)创建一个妻子线程类Wife
public class Account {
private String id;
private double balance;
public Account(String id, double balance) {
this.id = id;
this.balance = balance;
}
public synchronized void save(double money){
if(money > 0){
balance += money;
System.out.println("丈夫" + Thread.currentThread().getName() +"本次存钱" + money +"元," + this );
}
this.notify();
}
public synchronized void withdraw(double money){
while(money > balance){
System.out.println("妻子" + Thread.currentThread().getName() +"本次想取钱" + money +"元,余额不足,等待...");
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if(money > 0){
balance -= money;
System.out.println("妻子" + Thread.currentThread().getName() +"本次取钱" + money +"元," + this );
}
}
@Override
public String toString() {
return "账号:" + id +",余额:" + balance;
}
}
public class Husband extends Thread {
private Account account;
public Husband(String name, Account account) {
super(name);
this.account = account;
}
@Override
public void run(){
while(true){
account.save(Math.random()*9900+100);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class Wife extends Thread {
private Account account;
public Wife(String name, Account account) {
super(name);
this.account = account;
}
@Override
public void run() {
while(true){
account.withdraw(Math.random()*19000+1000);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class Exercise12 {
public static void main(String[] args) {
Account a = new Account("1122",0);
Husband h = new Husband("老王",a);
Wife w = new Wife("花花",a);
h.start();
w.start();
}
}