例子部分参考验证:
https://blog.csdn.net/qq_34996727/article/details/80416277?utm_medium=distribute.pc_relevant.none-task-blog-OPENSEARCH-3.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-OPENSEARCH-3.channel_param
1 实现线程执行单元
把标题从 1 创建线程 更新为 1 实现线程执行单元的方式。
java中只有Thread代表线程。Runnable只是将业务相关的代码抽象为一个接口。这涉及到一种设计模式:策略模式。
因此创建线程new线程的方式只有一种。
实现线程执行单元线程体的方式有两种。
例1.继承Thread类方式
代码:
package com.whl.thread;
/**
* 注:
* java.lang包中放着java最核心最基础的类、接口:Object、System、Thread、Runnable
* Thread.currentThread()获取当前cpu执行线程
*/
public class TestThread {
public static void main(String[] args) {
/**
* step 3:在方法中新建一个刚才写的类
*/
MyThread myThread = new MyThread();// 线程处于新建状态
myThread.start();// 就绪状态
for(int i = 0;i < 10;i++) {
System.out.println("hello "+Thread.currentThread().getName());
}
}
}
/**
* step 1:写一个类继承java.lang.Thread
*/
class MyThread extends Thread {
/**
* step 2:复写java.lang.Thread中的run()方法
*/
@Override
public void run() {// 运行
// TODO 你的线程代码
for(int i = 0;i < 10;i++) {
System.out.println("hello "+Thread.currentThread().getName());
}
}
}
运行结果:
例2.实现Runnable接口方式
代码
package com.whl.thread;
public class TestThread2 {
public static void main(String[] args) {
/**
* step 3:创建实现类
*/
MyRunnable myRunnable = new MyRunnable();
/**
* step 4:创建Thread,传入实现类
*/
Thread thread = new Thread(myRunnable);
/**
* step 5:调用start()方法
*/
thread.start();
for(int i = 0;i < 10;i++) {
System.out.println("hello "+Thread.currentThread().getName());
}
}
}
/**
* step 1:写一个Runnable接口的实现类
*/
class MyRunnable implements Runnable {
/**
* step 2:实现Runnable接口run()
*/
@Override
public void run() {
for(int i = 0;i < 10;i++) {
System.out.println("hello "+Thread.currentThread().getName());
}
}
}
运行结果
2 线程参数传递
例3.在实现类或继承类中写局部变量,通过有参构造、setget方式获取参数。
代码
package com.whl.thread;
public class TestThread3 {
public static void main(String[] args) {
/**
* step 3:创建线程,创建实现类中传递实参
*/
Thread t1 = new Thread(new MyRunnable2(23));
t1.start();
int i = 6;
while(i-- > 0){
System.out.println(Thread.currentThread().getName());
}
}
}
class MyRunnable2 implements Runnable {
/**
* step 1:在实现类中定义局部变量
*/
private int age;
/**
* step 2:定义有参构造方法
* @param age
*/
public MyRunnable2(int age) {
this.age = age;
}
@Override
public void run() {
int i = 6;
while(i-- > 0){
/**
* step 4:使用参数
*/
System.out.println(Thread.currentThread().getName() + " 我的年龄是->" + age);
}
}
}
运行结果
使用实现Runnable接口方式更好,原因:
java是单继承多实现;共享资源;数据和程序独立;
例4.两个线程共享资源实现代码:
package com.whl.thread;
public class TestThread3 {
public static void main(String[] args) {
MyRunnable2 myRunnable2 = new MyRunnable2();
myRunnable2.setAge(23);
// 两个线程共享变量age
Thread t1 = new Thread(myRunnable2);
Thread t2 = new Thread(myRunnable2);
t1.start();
t2.start();
int i = 10;
while(i-- > 0) {
System.out.println(Thread.currentThread().getName());
}
}
}
class MyRunnable2 implements Runnable {
/**
* step 1:在实现类中定义局部变量
* 两个线程共享
*/
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public void run() {
int i = 10;
while(i-- > 0){
this.age++;
System.out.println(Thread.currentThread().getName() + " 我的年龄是->" + age);
}
}
}
运行结果:
3 线程应用例子
例5. 3个站台同时出售火车票,火车票共有20张
代码实现:
package com.whl.example.station;
/**
* 注明:
* static: 在类中的类前加上static,直接通过类名.类名调用;
* 在类中的方法前加上static,直接通过类名.方法名调用;
* 在类中的变量前加上static,直接同多类名.变量名访问;
* 静态变量生命周期是类的生命周期;
*
* step 1: 创建一个站台类继承java.lang.Thread
*/
public class Station extends Thread {
/**
* step 2: 创建有参构造方法,给线程名称赋值
* @param name
*/
public Station(String name) {
super(name);
}
/**
* step 3:创建静态变量,类的变量
*/
static int tick = 20;
/**
* step 4: 创建静态钥匙,类的变量
*
* 关键思想:通过[静态,没有static关键字可正常运行]变量的占用判断是否对另一个静态变量操作
*/
Object lock = "one";
/**
* step 5: 重写run()方法,实现买票操作
*/
@Override
public void run() {
while(tick > 0) {
/**
* step 6: 每个线程使用同一静态变量,一个线程占用该静态变量时,其他线程不允许进入
* 该线程出来这个代码块后,不使用该静态变量
*
* 关键思想:synchronized与静态变量lock配合,操作系统保证cpu只运行三个线程中唯一一个线程中此段代码,
* 其他线程不能被执行。唯一一个线程的此段代码运行结束后,cpu可同步执行3个线程线程。
*/
synchronized (lock) {
if(tick > 0) {
System.out.println(getName()+"卖出了第"+tick+"张票");
tick--;
}else {
System.out.println("票卖完了");
}
}
try {
sleep(500);
} catch(Exception e) {
e.printStackTrace();
}
}
}
}
package com.whl.example.station;
public class Main {
public static void main(String[] args) {
/**
* step 7: 创建继承类售票窗口
* 3个窗口
*/
Thread t1 = new Station("售票窗口1号");
Thread t2 = new Station("售票窗口2号");
Thread t3 = new Station("售票窗口3号");
/**
* step 8: 三个窗口都处于就绪状态
*/
t1.start();
t2.start();
t3.start();
}
}
运行结果:
问题:同步关键字为什么不写在循环外?
同步关键字写在循环外面代码:
@Override
public void run() {
synchronized (lock){while(tick > 0) {
/**
* step 6: 每个线程使用同一静态变量,一个线程占用该静态变量时,其他线程不允许进入
* 该线程出来这个代码块后,不使用该静态变量
*
* 关键思想:synchronized与静态变量lock配合,操作系统保证cpu只运行三个线程中唯一一个线程中此段代码,
* 其他线程不能被执行。唯一一个线程的此段代码运行结束后,cpu可同步执行3个线程线程。
*/
if(tick > 0) {
System.out.println(getName()+"卖出了第"+tick+"张票");
tick--;
}else {
System.out.println("票卖完了");
}
try {
sleep(500);
} catch(Exception e) {
e.printStackTrace();
}
}
}}
运行结果:
结论:同步关键字修饰的代码块,被单独执行。
例6.两个人,一个人每次取钱100元,一个人每次取钱200元,账户里有1000元.
代码实现:
package com.whl.example.person;
import java.util.Objects;
/**
* step 1:创建银行类
*/
public class Bank {
/**
* 创建一个账户,放1000元
* [有没有 static 不影响结果]
*/
double money = 1000;
/**
* 提供柜台取钱方法
* @param money
*/
private void counter(double money) {
this.money -= money;
System.out.println("柜台取钱"+money+"元,还剩"+this.money+"元!");
}
/**
* 提供atm取钱方法
* @param money
*/
private void atm(double money) {
this.money -= money;
System.out.println("atm取钱"+money+"元,还剩"+this.money+"元!");
}
/**
* 核心:只要有一个线程被cpu正在执行这个取钱方法,其他都不准执行。
*
* 提供取钱方法,设置每次取钱金额,取钱方式
* @param money
* @param mode
* @throws Exception
*/
public synchronized void outMoney(double money,String mode) throws Exception {
if(money > this.money) {
throw new Exception("取款金额"+money+",余额只剩"+this.money+",取款失败!");
}
if(Objects.equals(mode,"atm")) {
atm(money);
}else {
counter(money);
}
}
}
package com.whl.example.person;
/**
* step 2:创建一个人继承java.lang.Thread
*/
public class PersonA extends Thread {
Bank bank;
String mode;
public PersonA(Bank bank,String mode) {
this.bank = bank;
this.mode = mode;
}
/**
* 每次取钱100,柜台取钱
*/
public void run(){
while(bank.money >= 100) {
try{
bank.outMoney(100,mode);
}catch (Exception e) {
e.printStackTrace();
}
try{
sleep(100);
}catch (Exception e) {
e.printStackTrace();
}
}
}
}
package com.whl.example.person;
/**
* step 3:创建一个人继承java.lang.Thread
*/
public class PersonB extends Thread {
/**
* 创建账户
*/
Bank bank;
/**
* 创建取钱方式
*/
String mode;
/**
* 提供设置具体取钱方式及账户的方法
* @param bank
* @param mode
*/
public PersonB(Bank bank,String mode) {
this.bank = bank;
this.mode = mode;
}
/**
* 每次取钱200元,atm取钱
*/
public void run(){
while(bank.money >= 200) {
try{
bank.outMoney(200,mode);
}catch (Exception e) {
e.printStackTrace();
}
try{
sleep(100);
}catch (Exception e) {
e.printStackTrace();
}
}
}
}
package com.whl.example.person;
/**
* step 4:创建一个入口类
*/
public class Main {
public static void main(String[] args) {
/**
* 实例化一个银行账户
*/
Bank bank = new Bank();
/**
* 实例化两个继承类,共享这个银行账户
*/
PersonA personA = new PersonA(bank,"counter");
PersonB personB = new PersonB(bank,"atm");
/**
* 线程处于就绪状态
*/
personA.start();
personB.start();
}
}
运行结果:
例7.龟兔赛跑
总共200米
乌龟0.1秒跑2米,不休息
兔子0.1秒跑5米,每20米休息1秒
一个赢了,另一个停止跑
实现代码:
package com.whl.example.animal;
public abstract class Animal extends Thread {
/**
* 比赛长度
*/
public int length = 200;
/**
* 抽象方法
* 动物跑
*/
public abstract void running();
/**
* 复写run()
*/
public void run(){
super.run();
while (length > 0) {
running();
}
}
/**
* 抽象类中声明一个接口
*/
public static interface Calltoback {
public void win();
}
/**
* 创建接口对象
*/
public Calltoback calltoback;
}
package com.whl.example.animal;
public class Rabbit extends Animal {
public Rabbit() {
setName("兔子");
}
@Override
public void running() {
int dis = 5;
length -= dis;
System.out.println("兔子跑了"+dis+"米,距离终点还有"+length+"米");
if(length <= 0) {
length = 0;
System.out.println("兔子赢了!");
// 给回调对象赋值,让乌龟不要跑了
if(calltoback != null) {
calltoback.win();
}
}
try {
if((2000 - length) % 20 == 0) {// 每20米休息一次
sleep(1000);
}else {
sleep(100);// 每0.1秒跑5米
}
}catch (Exception e) {
e.printStackTrace();
}
}
}
package com.whl.example.animal;
public class Tortoise extends Animal {
public Tortoise() {
setName("乌龟");
}
@Override
public void running() {
int dis = 2;
length -= dis;
System.out.println("乌龟跑了"+dis+"米,距离终点还有"+length+"米");
if(length <= 0) {
length = 0;
System.out.println("乌龟赢了!");
if(calltoback != null) {
calltoback.win();
}
}
try {
sleep(100);// 跑2米停0.1秒 -> 每0.1秒跑2米
} catch (Exception e) {
e.printStackTrace();
}
}
}
package com.whl.example.animal;
public class LetOneStop implements Animal.Calltoback {
Animal animal;
public LetOneStop(Animal animal) {
this.animal = animal;
}
public void win(){
// 线程停止
animal.stop();
}
}
package com.whl.example.animal;
public class Main {
public static void main(String[] args) {
// 乌龟
Tortoise tortoise = new Tortoise();
// 兔子
Rabbit rabbit = new Rabbit();
// 兔子赢了,将乌龟停止
LetOneStop letOneStop1 = new LetOneStop(tortoise);
rabbit.calltoback = letOneStop1;
// 乌龟赢了,将兔子停止
LetOneStop letOneStop2 = new LetOneStop(rabbit);
tortoise.calltoback = letOneStop2;
// 跑
tortoise.start();
rabbit.start();
}
}
运行结果: