Thread 类的方式实现多线程【应用】
Thread 类run() 方法start() 方法启动线程 方法名说明void run()线程启动后,此方法将被自动调用,用于定义线程的执行逻辑void start()启动线程,Java虚拟机会自动调用 run() 方法
public class MyThread extends Thread{
@Override
public void run(){
//书写线程要执行代码
for (int i = 0; i < 100; i++) {
System.out.println(getName()+" "+ "100次循环");
}
}
}
public class main {
public static void main(String[] args) {
MyThread t1=new MyThread();
MyThread t2=new MyThread();
MyThread t3=new MyThread();
MyThread t4=new MyThread();
t1.setName("线程1");
t2.setName("线程2");
t3.setName("线程3");
t4.setName("线程4");
t1.start();
t2.start();
t3.start();
t4.start();
}
}方法名 | 说明 |
|---|---|
void run() | 在线程开启后,此方法将被调用执行 |
void start() | 使此线程开始执行,Java虚拟机会调用run方法() |
public class MyRunnable implements Runnable{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
//获取到当前线程的对象
Thread t = Thread.currentThread();
//书写线程执行代码
System.out.println(t.getName()+"再来一百次");
}
}
}
public class main {
public static void main(String[] args) {
//表示多线程要执行的任务
MyRunnable mr1=new MyRunnable();
//创建线程对象
Thread t1=new Thread(mr1);
Thread t2=new Thread(mr1);
//给线程设置名字
t1.setName("线程1");
t2.setName("线程2");
//开启线程
t1.start();
t2.start();
}
}2.3 利用Callable接口和Future接口方式实现【应用】
public class MyThread extends Thread{
@Override
public void run(){
//书写线程要执行代码
for (int i = 0; i < 100; i++) {
System.out.println(getName()+" "+ "100次循环");
}
}
}
public class main {
public static void main(String[] args) {
MyThread t1=new MyThread();
MyThread t2=new MyThread();
MyThread t3=new MyThread();
MyThread t4=new MyThread();
t1.setName("线程1");
t2.setName("线程2");
t3.setName("线程3");
t4.setName("线程4");
t1.start();
t2.start();
t3.start();
t4.start();
}
}2.4 三种实现方式的对比【理解】
方法名 | 说明 |
|---|---|
String getName() | 返回此线程的名称 |
void setName(String name) | 设置线程的名字(构造方法也可以设置名字) |
static Thread currentThread() | 获取当前线程的对象 |
static void sleep(long time) | 让线程休眠指定的时间,单位为毫秒 |
setPriority(int newPriority) | 设置线程的优先级 |
final int getPriority() | 获取线程的优先级 |
final void setDaemon(boolean on) | 设置为守护线程 |
public static void yield() | 出让线程/礼让线程 |
public static void join | 插入线程/插队线程 |
接下来,以线程基础,线程优先级,守护线程,礼让线程,插入线程的几个角度去拆分
方法名 | 说明 |
|---|---|
String getName() | 返回此线程的名称 |
void setName(String name) | 设置线程的名字(构造方法也可以设置名字) |
static Thread currentThread() | 获取当前线程的对象 |
public class MyThread extends Thread{
public MyThread() {
}
public MyThread(String name) {
super(name);
}
@Override
public void run() {
for (int i = 0; i < 101; i++) {
System.out.println(getName() + "@" + i);
}
}
}
public class Demo1 {
public static void main(String[] args) {
//创建线程对象
MyThread t1=new MyThread();
MyThread t2=new MyThread("飞机");
//开启线程
t1.start();
t2.start();
}方法名 | 说明 |
|---|---|
setPriority(int newPriority) | 设置线程的优先级 |
final int getPriority() | 获取线程的优先级 |
public class MyRunnable implements Runnable{
@Override
public void run() {
for (int i = 0; i < 101; i++) {
System.out.println(Thread.currentThread().getName()+"---"+i);
}
}
}
public class Demo1 {
public static void main(String[] args) {
//创建线程要执行的参数对象
MyRunnable mr=new MyRunnable();
//创建线程对象
Thread t1=new Thread(mr,"飞机");
Thread t2=new Thread(mr,"坦克");
t1.setPriority(1);
t2.setPriority(10);
System.out.println(Thread.currentThread().getPriority());
}
}注:此处优先级最高是10,最小是1,默认为5
public static final int MIN_PRIORITY = 1;
public static final int NORM_PRIORITY = 5;
public static final int MAX_PRIORITY = 10;方法名 | 说明 |
|---|---|
void setDaemon(boolean on) | 将此线程标记为守护线程,当运行的线程都是守护线程时,Java虚拟机将退出 |
public class main {
public static void main(String[] args) {
// final void setDaemon(boolean on) 设置为守护线程
MyThread1 mr1=new MyThread1("女神");
MyThread2 mr2=new MyThread2("天沟");
//此处设置完,当mr1结束之后,mr2会短时间内终止进程,不管进程是否结束
mr2.setDaemon(true);
mr1.start();
mr2.start();
}
}方法名 | 说明 |
|---|---|
public static void yield( ) | 出让线程/礼让线程 |
public class MyThread extends Thread{
@Override
public void run(){
for (int i = 0; i < 101; i++) {
System.out.println(getName()+"@"+i);
}
//出让当前CPU执行权
Thread.yield();
}
}
public class main {
public static void main(String[] args) {
//public static void yield() 出让线程/礼让线程
MyThread t1=new MyThread();
MyThread2 t2=new MyThread2();
t1.setName("NPC1号");
t2.setName("NPC2号");
t1.start();
t2.start();
}
}注意点:这个方法只是尽可能的均匀一点,并非绝对,简单了解即可
方法名 | 说明 |
|---|---|
public final void join( ) | 插入线程/插队线程 |
public class main {
public static void main(String[] args) throws InterruptedException {
MyThread t=new MyThread();
t.setName("土豆");
t.start();
//把t线程插入到当前线程之前
t.join();
//执行在main线程当中的
for (int i = 0; i < 10; i++) {
System.out.println("main线程"+i);
}
}
}需求: 某电影院目前正在上映国产大片,共有100张票,而它有3个窗口卖票,请设计一个程序模拟该电影院卖票
//Thread类
public class MyThread extends Thread{
static int ticket =0;
@Override
public void run(){
while (true){
if (ticket<100){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
ticket++;
System.out.println(getName()+"正在卖"+ticket+"张票!");
}else {
break;
}
}
}
}
//主入口
public class main {
public static void main(String[] args) {
MyThread mr1=new MyThread();
MyThread mr2=new MyThread();
MyThread mr3=new MyThread();
//起名字
mr1.setName("窗口1");
mr2.setName("窗口2");
mr3.setName("窗口3");
//开启线程
mr1.start();
mr2.start();
mr3.start();
}
}synchronized(任意对象) { 多条语句操作共享数据的代码 }
//Thread类
public class MyThread extends Thread{
static int ticket =0;
@Override
public void run(){
while (true){
synchronized(MyThread.class){
if (ticket<100){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
ticket++;
System.out.println(getName()+"正在卖"+ticket+"张票!");
}else {
break;
}
}
}
}
}
//测试类
public class main {
public static void main(String[] args) {
MyThread mr1=new MyThread();
MyThread mr2=new MyThread();
MyThread mr3=new MyThread();
//起名字
mr1.setName("窗口1");
mr2.setName("窗口2");
mr3.setName("窗口3");
//开启线程
mr1.start();
mr2.start();
mr3.start();
}
}修饰符 synchronized 返回值类型 方法名(方法参数) { 方法体; }
//Runnable类
public class MyRunnable implements Runnable {
int ticket = 0;
@Override
public void run() {
while (true) {
if (method()){
break;
}
}
}
private synchronized boolean method() {
if (ticket == 100) {
return true;
}
if (ticket < 100) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(Thread.currentThread().getName() + "正在卖第" + ticket + "张票");
ticket++;
}
return false;
}
}
//测试类
public class main {
public static void main(String[] args) {
MyRunnable mr=new MyRunnable();
Thread t1=new Thread(mr);
Thread t2=new Thread(mr);
Thread t3=new Thread(mr);
t1.setName("窗口1");
t2.setName("窗口2");
t3.setName("窗口3");
t1.start();
t2.start();
t3.start();
}
}方法 | 说明 |
|---|---|
void lock( ) | 获得锁 |
void unlock( ) | 释放锁 |
//Thread类
public class MyThread extends Thread {
static int ticket = 0;
static Lock lock = new ReentrantLock();
@Override
public void run() {
while (true) {
lock.lock();
try {
if (ticket == 100) {
break;
} else {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
ticket++;
System.out.println(getName() + "正在卖" + ticket + "张票!");
}
} catch (RuntimeException e) {
throw new RuntimeException(e);
}finally {
lock.unlock();
}
}
}
}
//测试类
public class main {
public static void main(String[] args) {
/*
某电影院目前正在上映国产大片,共有100张票,而它有3个窗口卖票
请设计一个程序模拟该电影院卖票
*/
MyThread mr1=new MyThread();
MyThread mr2=new MyThread();
MyThread mr3=new MyThread();
//起名字
mr1.setName("窗口1");
mr2.setName("窗口2");
mr3.setName("窗口3");
//开启线程
mr1.start();
mr2.start();
mr3.start();
}
}注:死锁不是知识点,是错误,为了防止以后犯的错误
public class MyThread extends Thread {
static Object objA = new Object();
static Object objB = new Object();
@Override
public void run() {
//1.循环
while (true) {
if ("线程A".equals(getName())) {
synchronized (objA) {
System.out.println("线程A拿到了A锁,准备拿B锁");//A
synchronized (objB) {
System.out.println("线程A拿到了B锁,顺利执行完一轮");
}
}
} else if ("线程B".equals(getName())) {
if ("线程B".equals(getName())) {
synchronized (objB) {
System.out.println("线程B拿到了B锁,准备拿A锁");//B
synchronized (objA) {
System.out.println("线程B拿到了A锁,顺利执行完一轮");
}
}
}
}
}
}
}方法名 | 说明 |
|---|---|
void wait() | 导致当前线程等待,直到另一个线程调用该对象的 notify()方法或 notifyAll()方法 |
void notify() | 唤醒正在等待对象监视器的单个线程 |
void notifyAll() | 唤醒正在等待对象监视器的所有线程 |
public class Desk {
//定义一个标记
//true 就表示桌子上有汉堡包的,此时允许吃货执行
//false 就表示桌子上没有汉堡包的,此时允许厨师执行
public static boolean flag = false;
//汉堡包的总数量
public static int count = 10;
//锁对象
public static final Object lock = new Object();
}
public class Cooker extends Thread {
// 生产者步骤:
// 1,判断桌子上是否有汉堡包
// 如果有就等待,如果没有才生产。
// 2,把汉堡包放在桌子上。
// 3,叫醒等待的消费者开吃。
@Override
public void run() {
while(true){
synchronized (Desk.lock){
if(Desk.count == 0){
break;
}else{
if(!Desk.flag){
//生产
System.out.println("厨师正在生产汉堡包");
Desk.flag = true;
Desk.lock.notifyAll();
}else{
try {
Desk.lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
}
public class Foodie extends Thread {
@Override
public void run() {
// 1,判断桌子上是否有汉堡包。
// 2,如果没有就等待。
// 3,如果有就开吃
// 4,吃完之后,桌子上的汉堡包就没有了
// 叫醒等待的生产者继续生产
// 汉堡包的总数量减一
//套路:
//1. while(true)死循环
//2. synchronized 锁,锁对象要唯一
//3. 判断,共享数据是否结束. 结束
//4. 判断,共享数据是否结束. 没有结束
while(true){
synchronized (Desk.lock){
if(Desk.count == 0){
break;
}else{
if(Desk.flag){
//有
System.out.println("吃货在吃汉堡包");
Desk.flag = false;
Desk.lock.notifyAll();
Desk.count--;
}else{
//没有就等待
//使用什么对象当做锁,那么就必须用这个对象去调用等待和唤醒的方法.
try {
Desk.lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
}
public class Demo {
public static void main(String[] args) {
/*消费者步骤:
1,判断桌子上是否有汉堡包。
2,如果没有就等待。
3,如果有就开吃
4,吃完之后,桌子上的汉堡包就没有了
叫醒等待的生产者继续生产
汉堡包的总数量减一*/
/*生产者步骤:
1,判断桌子上是否有汉堡包
如果有就等待,如果没有才生产。
2,把汉堡包放在桌子上。
3,叫醒等待的消费者开吃。*/
Foodie f = new Foodie();
Cooker c = new Cooker();
f.start();
c.start();
}
}
方法 | 说明 |
|---|---|
put(anObject) | 将参数放入队列,如果放不进去会阻塞 |
take() | 取出第一个数据,取不到会阻塞 |
public class Cooker extends Thread {
private ArrayBlockingQueue<String> bd;
public Cooker(ArrayBlockingQueue<String> bd) {
this.bd = bd;
}
// 生产者步骤:
// 1,判断桌子上是否有汉堡包
// 如果有就等待,如果没有才生产。
// 2,把汉堡包放在桌子上。
// 3,叫醒等待的消费者开吃。
@Override
public void run() {
while (true) {
try {
bd.put("汉堡包");
System.out.println("厨师放入一个汉堡包");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class Foodie extends Thread {
private ArrayBlockingQueue<String> bd;
public Foodie(ArrayBlockingQueue<String> bd) {
this.bd = bd;
}
@Override
public void run() {
// 1,判断桌子上是否有汉堡包。
// 2,如果没有就等待。
// 3,如果有就开吃
// 4,吃完之后,桌子上的汉堡包就没有了
// 叫醒等待的生产者继续生产
// 汉堡包的总数量减一
//套路:
//1. while(true)死循环
//2. synchronized 锁,锁对象要唯一
//3. 判断,共享数据是否结束. 结束
//4. 判断,共享数据是否结束. 没有结束
while (true) {
try {
String take = bd.take();
System.out.println("吃货将" + take + "拿出来吃了");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class Demo {
public static void main(String[] args) {
ArrayBlockingQueue<String> bd = new ArrayBlockingQueue<>(1);
Foodie f = new Foodie(bd);
Cooker c = new Cooker(bd);
f.start();
c.start();
}
}细节: 生产者和消费者必须使用同一个阻塞队列
几个案例代码不一定和黑马一样,仅供参考
//Thread类
public class MyThread extends Thread{
static int ticket = 1000;
static Lock lock = new ReentrantLock();
@Override
public void run() {
while (true){
lock.lock();
if (ticket==0){
break;
}else {
try {
sleep(3000);
ticket--;
System.out.println(getName()+"卖了一张票,还剩下"+ticket+"张票");
} catch (InterruptedException e) {
throw new RuntimeException(e);
}finally {
lock.unlock();
}
}
}
}
}
//测试类
public class main {
public static void main(String[] args) {
//一共有1000张电影票,可以在两个窗口领取,假设每次领取时间为3000毫秒
//要求:用多线程模拟卖票过程并打印剩余电影票数量
MyThread mr1=new MyThread();
MyThread mr2=new MyThread();
mr1.setName("窗口1");
mr2.setName("窗口2");
mr1.start();
mr2.start();
}
}//MyThread类
public class MyThread extends Thread{
static int gift = 100;
static Lock lock = new ReentrantLock();
@Override
public void run() {
while (true){
lock.lock();
if (gift<10){
break;
}else {
try {
sleep(3);
gift--;
System.out.println(getName()+"送了一个礼物,还剩下"+gift+"个礼物");
} catch (InterruptedException e) {
throw new RuntimeException(e);
}finally {
lock.unlock();
}
}
}
}
}
//测试类
public class main {
public static void main(String[] args) {
MyThread mr1=new MyThread();
MyThread mr2=new MyThread();
mr1.setName("小明");
mr2.setName("小红");
mr1.start();
mr2.start();
}
}//MyThread类
public class MyThread extends Thread{
static int i=0;
@Override
public void run() {
while (true){
synchronized (MyThread.class){
if (i==100){
break;
}else {
if (i%2==1){
System.out.println(i);
i++;
}else {
i++;
}
}
}
}
}
}
//测试类
public class main {
public static void main(String[] args) {
MyThread mr1=new MyThread();
MyThread mr2=new MyThread();
mr1.start();
mr2.start();
}
}XXX抢到了XXX元 XXX抢到了XXX元 XXX抢到了XXX元 XXX没抢到 XXX没抢到
//Thread类
public class Person extends Thread {
static int redPacket = 3;
static double money = 100;
@Override
public void run() {
synchronized (Person.class) {
if (redPacket == 0) {
System.out.println(getName() + "没抢到");
} else if (redPacket == 1) {
redPacket--;
System.out.println(getName() + "抢到了" + money + "元,当前红包以抢完");
} else {
double s = Math.random() * money;
money = money - s;
redPacket--;
System.out.println(getName() + "抢到了" + s + "元,当前还剩" + redPacket + "个红包");
}
}
}
}
//测试类
public class main {
public static void main(String[] args) {
Person t1=new Person();
Person t2=new Person();
Person t3=new Person();
Person t4=new Person();
Person t5=new Person();
t1.setName("用户1");
t2.setName("用户2");
t3.setName("用户3");
t4.setName("用户4");
t5.setName("用户5");
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
}
}每次抽出一个奖项就打印一个(随机) 抽奖箱1 又产生了一个 10 元大奖 抽奖箱1 又产生了一个 100 元大奖 抽奖箱1 又产生了一个 200 元大奖 抽奖箱1 又产生了一个 800 元大奖 抽奖箱2 又产生了一个 700 元大奖
//Thread类
public class LuckyDraw extends Thread{
static ArrayList<Integer> number=new ArrayList<>();
public LuckyDraw(ArrayList a) {
number=a;
}
@Override
public void run() {
while (true){
synchronized (LuckyDraw.class){
if (number.size()==0){
break;
}else {
Collections.shuffle(number);
Integer remove = number.remove(0);
System.out.println(getName()+"又产生了一个"+remove+"元大奖");
}
}
try {
Thread.sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
//测试类
public class main {
public static void main(String[] args) {
ArrayList<Integer> list=new ArrayList<>();
Collections.addAll(list,10,5,20,50,100,200,500,800,2,80,300,700);
LuckyDraw t1=new LuckyDraw(list);
LuckyDraw t2=new LuckyDraw(list);
t1.setName("抽奖箱1");
t2.setName("抽奖箱2");
t1.start();
t2.start();
}
}//Thread类
public class LuckyDraw extends Thread {
static ArrayList<Integer> number = new ArrayList<>();
int sum = 0;
public LuckyDraw(ArrayList a) {
number = a;
}
@Override
public void run() {
ArrayList<Integer> box = new ArrayList<>();
while (true) {
synchronized (LuckyDraw.class) {
if (number.size() == 0) {
Collections.sort(box);
StringBuilder sb1 = new StringBuilder();
for (int i = 0; i < box.size(); i++) {
sum = sum + box.get(i);
if (i == (box.size() - 1)) {
sb1.append(box.get(i));
System.out.println("在此抽奖过程中" + getName() + "总共产生了6个选项,分别为:" + sb1 + "最高奖项为" + Collections.max(box) + "总金额为" + sum + "元");
break;
} else {
sb1.append(box.get(i) + ",");
}
}
break;
} else {
Collections.shuffle(number);
Integer remove = number.remove(0);
box.add(remove);
}
}
try {
Thread.sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
//测试类
public class main {
public static void main(String[] args) {
ArrayList<Integer> list=new ArrayList<>();
Collections.addAll(list,10,5,20,50,100,200,500,800,2,80,300,700);
LuckyDraw t1=new LuckyDraw(list);
LuckyDraw t2=new LuckyDraw(list);
t1.setName("抽奖箱1");
t2.setName("抽奖箱2");
t1.start();
t2.start();
}
}//Callable类
public class LuckyDraw implements Callable<Integer> {
static ArrayList<Integer> number = new ArrayList<>();
int sum = 0;
int max=0;
public LuckyDraw(ArrayList a) {
number = a;
}
@Override
public Integer call() throws Exception {
ArrayList<Integer> box = new ArrayList<>();
while (true) {
synchronized (LuckyDraw.class) {
if (number.size() == 0) {
Collections.sort(box);
StringBuilder sb1 = new StringBuilder();
if (box.size()==0){
return null;
}
for (int i = 0; i < box.size(); i++) {
sum = sum + box.get(i);
if (i == (box.size() - 1)) {
sb1.append(box.get(i));
max=Collections.max(box);
System.out.println("在此抽奖过程中" + Thread.currentThread().getName() + "总共产生了6个选项,分别为:" + sb1 + "最高奖项为" + max + "总金额为" + sum + "元");
break;
} else {
sb1.append(box.get(i) + ",");
}
}
break;
} else {
Collections.shuffle(number);
Integer remove = number.remove(0);
box.add(remove);
}
}
Thread.sleep(10);
}
return max;
}
}
//测试类
public class main {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ArrayList<Integer> list=new ArrayList<>();
Collections.addAll(list,10,5,20,50,100,200,500,800,2,80,300,700);
LuckyDraw l1=new LuckyDraw(list);
FutureTask<Integer> ft1=new FutureTask<>(l1);
FutureTask<Integer> ft2=new FutureTask<>(l1);
Thread t1=new Thread(ft1);
Thread t2=new Thread(ft2);
t1.setName("抽奖箱1");
t2.setName("抽奖箱2");
t1.start();
t2.start();
Integer max1=ft1.get();
Integer max2=ft2.get();
System.out.println(max1);
System.out.println(max2);
}
}Executors:线程池的工具类通过调用方法返回不同类型的线程池对象
方法名 | 说明 |
|---|---|
public static ExecutorService newCachedThreadPool( ) | 创建一个没有上限的线程池 |
public static ExecutorService newCachedThreadPool(int nThreads) | 创建有上限的线程池 |
//Runnable类
public class MyRunnable implements Runnable{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName()+i);
}
}
}
//测试类
public class main {
public static void main(String[] args) {
//获得线程池对象
ExecutorService pool1 = Executors.newCachedThreadPool();
//提交任务
pool1.submit(new MyRunnable());
//销毁线程池[一般不会销毁]
pool1.shutdown();
}
}