【java】多线程
创始人
2024-03-12 05:40:01
0

文章目录

  • 进程和线程
  • 继承Thread类的方式实现多线程
  • 设置和获取线程的名称
  • 线程优先级 线程调度
  • 控制线程
  • 线程的生命周期
  • 多线程的实现方式
  • 案例--卖票
  • 同步方法解决数据安全问题
    • 线程安全的类
  • Lock锁
  • 生产者消费者模式
    • 概述
    • 案例

进程和线程

在这里插入图片描述
在这里插入图片描述

继承Thread类的方式实现多线程

在这里插入图片描述
MyThread.java

package heima.多线程;public class MyThread extends Thread{@Overridepublic void run(){for (int i = 0;i<100;i++){System.out.println(i);}}
}
package heima.多线程;public class P1 {public static void main(String[] args) {MyThread my1 = new MyThread();MyThread my2 = new MyThread();//        my1.run();
//        my2.run();//1~99//void start():导致此现场开始执行;java虚拟机调用此线程的run方法my1.start();my2.start();//1~99//两者区别//run:相当于普通的调用//start:启动线程;然后由虚拟机调用此线程的run()方法}
}

设置和获取线程的名称

在这里插入图片描述
MyThread.java

package heima.多线程;public class MyThread extends Thread{public MyThread(){}public MyThread(String name){super(name);}@Overridepublic void run(){for (int i = 0;i<100;i++){System.out.println(getName()+":"+i);}}
}
package heima.多线程;public class P2 {public static void main(String[] args) {
//        MyThread my1 = new MyThread();
//        MyThread my2 = new MyThread();//1.void setName(String name):将此线程的名称更改位大于参数name
//        my1.setName("高铁");
//        my2.setName("飞机");//2.Thread(String name):带参构造方法--需要对MyThread内部进行修改
//        MyThread my1 = new MyThread("高铁");
//        MyThread my2 = new MyThread("飞机");
//
//        my1.start();
//        my2.start();//3.static Thread currentThread():返回对当前正在执行的线程对象的引用System.out.println(Thread.currentThread().getName());}
}

方法1和方法2的输出:
在这里插入图片描述

方法3的输出:
在这里插入图片描述

线程优先级 线程调度


ThreadPriority.java

package heima.多线程;public class ThreadPriority extends Thread{@Overridepublic void run() {for (int i = 0;i<100;i++){System.out.println(getName()+":"+i);}}
}

//后面是输出

package heima.多线程;public class P3 {public static void main(String[] args) {ThreadPriority tp1 = new ThreadPriority();ThreadPriority tp2 = new ThreadPriority();ThreadPriority tp3 = new ThreadPriority();tp1.setName("高铁");tp2.setName("飞机");tp3.setName("汽车");//        tp1.start();
//        tp2.start();
//        tp3.start();//public final int getPriority():返回此线程的优先级
//        System.out.println(tp1.getPriority());//5
//        System.out.println(tp2.getPriority());//5
//        System.out.println(tp3.getPriority());//5
//
//        //public final void setPriority(int newPriority):更改此线程的优先级
        tp1.setPriority(10000);//IllegalArgumentException
//        System.out.println(Thread.MAX_PRIORITY);//10
//        System.out.println(Thread.MIN_PRIORITY);//1
//        System.out.println(Thread.NORM_PRIORITY);//5//正确设置优先级tp1.setPriority(5);tp2.setPriority(10);tp3.setPriority(1);tp1.start();tp2.start();tp3.start();}
}

计算设置了优先级也同样还是有随机性,需要在次数较多的时候才能看到想要的效果

控制线程

在这里插入图片描述

  • sleep
package heima.多线程.other;public class ThreadSleep extends Thread{@Overridepublic void run() {for (int i = 0;i<100;i++){System.out.println(getName()+":"+i);try {//sleep使三人轮流抢到cpu时间,看上去更加和谐Thread.sleep(1000);}catch (InterruptedException e){e.printStackTrace();}}}
}
package heima.多线程;import heima.多线程.other.ThreadSleep;public class P4 {public static void main(String[] args) {ThreadSleep ts1 = new ThreadSleep();ThreadSleep ts2 = new ThreadSleep();ThreadSleep ts3 = new ThreadSleep();ts1.setName("曹操");ts2.setName("刘备");ts3.setName("孙权");ts1.start();ts2.start();ts3.start();}
}
  • join
package heima.多线程;import heima.多线程.other.ThreadSleep;public class P4 {public static void main(String[] args) {ThreadSleep ts1 = new ThreadSleep();ThreadSleep ts2 = new ThreadSleep();ThreadSleep ts3 = new ThreadSleep();ts1.setName("曹操");ts2.setName("刘备");ts3.setName("孙权");ts1.start();//void join():等待这个线程死亡try{ts1.join();}catch (InterruptedException e){e.printStackTrace();}ts2.start();ts3.start();}
}

在这里插入图片描述

  • setDaemon
package heima.多线程;import heima.多线程.other.ThreadSleep;public class P4 {public static void main(String[] args) {ThreadSleep ts1 = new ThreadSleep();ThreadSleep ts2 = new ThreadSleep();ThreadSleep ts3 = new ThreadSleep();ts1.setName("关羽");ts2.setName("张飞");//设置主线程为刘备Thread.currentThread().setName("刘备");//设置守护线程ts1.setDaemon(true);ts2.setDaemon(true);ts1.start();ts2.start();for (int i = 0;i<10;i++){System.out.println(Thread.currentThread().getName()+":"+i);}}
}

线程的生命周期

在这里插入图片描述

多线程的实现方式

在这里插入图片描述

在这里插入图片描述
MyRunnable.java

package heima.多线程.other;public class MyRunnable implements Runnable{@Overridepublic void run() {for (int i = 0;i<100;i++){System.out.println(Thread.currentThread().getName()+":"+i);}}
}
package heima.多线程;import heima.多线程.other.MyRunnable;public class P5 {public static void main(String[] args) {//创建MyRunnable类的对象MyRunnable my = new MyRunnable();//创建Thread类的对象,吧MyRunnable对象作为构造方法的参数//Thread(Runnable target)
//    Thread t1 = new Thread(my);
//    Thread t2 = new Thread(my);//Thread(Runnable target,String name)Thread t1 = new Thread(my,"高铁");Thread t2 = new Thread(my,"飞机");//启动线程t1.start();t2.start();}}

案例–卖票

在这里插入图片描述

package heima.多线程;import heima.多线程.other.SellTicket;public class P6 {public static void main(String[] args) {//创建SellTicket类的对象SellTicket st = new SellTicket();//创建三个Thread类的对象,把SellTicket对象作为构造方法的参数,并给出对应的窗口名称Thread t1 = new Thread(st,"窗口1");Thread t2 = new Thread(st,"窗口2");Thread t3 = new Thread(st,"窗口3");//启动线程t1.start();t2.start();t3.start();}
}
package heima.多线程.other;public class SellTicket implements Runnable{//在SellTicket类中重写run()实现卖票private int tickets = 100;@Overridepublic void run() {while (true){if (tickets > 0){System.out.println(Thread.currentThread().getName()+"正在出售第"+tickets+"张票");tickets--;}}}
}
  • 卖票案例的改进

在这里插入图片描述

在这里插入图片描述
way:
在这里插入图片描述

package heima.多线程.other;public class SellTicket implements Runnable{//在SellTicket类中重写run()实现卖票private int tickets = 100;private Object obj = new Object();@Overridepublic void run() {//加上代码锁,使每次只能进来一个对象synchronized (obj){while (true){if (tickets > 0){try {//让卖票动作更符合现实情况Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+"正在出售第"+tickets+"张票");tickets--;}}}}
}

在这里插入图片描述

同步方法解决数据安全问题

在这里插入图片描述

详情请见 黑马P334

线程安全的类

在这里插入图片描述
在这里插入图片描述

Lock锁

在这里插入图片描述

package heima.多线程.other;import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class SellTicket implements Runnable{//在SellTicket类中重写run()实现卖票private int tickets = 100;private Object obj = new Object();private Lock lock = new ReentrantLock();@Overridepublic void run() {while (true){try {lock.lock();if (tickets > 0){try {Thread.sleep(100);}catch (InterruptedException e){e.printStackTrace();}System.out.println(Thread.currentThread().getName()+"正在出售第"+tickets+"张票");tickets--;}//最后使用finally,使得就算报错最后也可以关闭锁}finally {lock.unlock();}}}
}

生产者消费者模式

概述

在这里插入图片描述
在这里插入图片描述

案例

在这里插入图片描述

  • 步骤1:先创建好基本的框架

BoxDemo.java

package heima.生产者消费者;public class BoxDemo {public static void main(String[] args) {//创建奶箱对象,这是共享数据区域Box b = new Box();//创建生产者对象,把奶箱对象作为构造方法参数传递,因为在这个类中要调用存储牛奶的操作Producter p = new Producter(b);//创建消费者对象,把奶箱对象作为构造方法参数传递,以为在这个类中要调用获取牛奶的操作Customer c = new Customer(b);//创建两个线程对象,分别把生产者和消费者对象作为构造方法参数传递Thread t1 = new Thread(p);Thread t2 = new Thread(c);//启动线程t1.start();t2.start();}
}

Customer.java

package heima.生产者消费者;public class Customer implements Runnable{private Box b;public Customer(Box b){this.b = b;}@Overridepublic void run() {while (true) {b.get();}}
}

Producter.java

package heima.生产者消费者;public class Producter implements Runnable{private Box b;public Producter(Box b){this.b = b;}@Overridepublic void run() {for (int i = 1;i<=5;i++){b.put(i);}}
}

Box.java

package heima.生产者消费者;public class Box {//定义一个成员变量,表示第x瓶奶private int milk;//提供存储牛奶和获取牛奶的操作public void put(int milk){this.milk = milk;System.out.println("送奶工将第"+this.milk+"瓶奶放入奶箱");}public void get(){System.out.println("用户拿到第"+this.milk+"瓶奶");}
}

输出一直卡死在最后的第5瓶奶上:
在这里插入图片描述

  • 步骤2
  1. 定义奶箱状态,并进行状态判断是否等待
  2. 等待需要配对对应的锁:synchronized
  3. 在等待的同步需要:唤醒其他等待的线程notifyAll

完整版

package heima.生产者消费者;public class Box {//定义一个成员变量,表示第x瓶奶private int milk;//定义一个成员变量,表示奶箱的状态private boolean state = false;//提供存储牛奶和获取牛奶的操作public synchronized void put(int milk){//如果有牛奶,等待消费if (state){try {wait();} catch (InterruptedException e) {e.printStackTrace();}}//如果没有牛奶,就生产牛奶this.milk = milk;System.out.println("送奶工将第"+this.milk+"瓶奶放入奶箱");//生产完毕之后,修改牛奶的状态state = true;//唤醒其他等待的线程notifyAll();}public synchronized void get() {//如果没有牛奶,等待生产if (!state) {try {wait();} catch (InterruptedException e) {e.printStackTrace();}}//如果有牛奶,就消费牛奶System.out.println("用户拿到第" + this.milk + "瓶奶");//消费完毕之后,修改奶箱状态state = false;//唤醒其他等待的线程notifyAll();}
}
package heima.生产者消费者;public class Producter implements Runnable{private Box b;public Producter(Box b){this.b = b;}@Overridepublic void run() {for (int i = 1;i<=5;i++){b.put(i);}}
}
package heima.生产者消费者;public class Customer implements Runnable{private Box b;public Customer(Box b){this.b = b;}@Overridepublic void run() {while (true) {b.get();}}
}
package heima.生产者消费者;public class BoxDemo {public static void main(String[] args) {//创建奶箱对象,这是共享数据区域Box b = new Box();//创建生产者对象,把奶箱对象作为构造方法参数传递,因为在这个类中要调用存储牛奶的操作Producter p = new Producter(b);//创建消费者对象,把奶箱对象作为构造方法参数传递,以为在这个类中要调用获取牛奶的操作Customer c = new Customer(b);//创建两个线程对象,分别把生产者和消费者对象作为构造方法参数传递Thread t1 = new Thread(p);Thread t2 = new Thread(c);//启动线程t1.start();t2.start();}
}

在这里插入图片描述

相关内容

热门资讯

美国2年期国债收益率上涨15个... 原标题:美国2年期国债收益率上涨15个基点 美国2年期国债收益率上涨15个基...
汽车油箱结构是什么(汽车油箱结... 本篇文章极速百科给大家谈谈汽车油箱结构是什么,以及汽车油箱结构原理图解对应的知识点,希望对各位有所帮...
嵌入式 ADC使用手册完整版 ... 嵌入式 ADC使用手册完整版 (188977万字)💜&#...
重大消息战皇大厅开挂是真的吗... 您好:战皇大厅这款游戏可以开挂,确实是有挂的,需要了解加客服微信【8435338】很多玩家在这款游戏...
盘点十款牵手跑胡子为什么一直... 您好:牵手跑胡子这款游戏可以开挂,确实是有挂的,需要了解加客服微信【8435338】很多玩家在这款游...
senator香烟多少一盒(s... 今天给各位分享senator香烟多少一盒的知识,其中也会对sevebstars香烟进行解释,如果能碰...
终于懂了新荣耀斗牛真的有挂吗... 您好:新荣耀斗牛这款游戏可以开挂,确实是有挂的,需要了解加客服微信8435338】很多玩家在这款游戏...
盘点十款明星麻将到底有没有挂... 您好:明星麻将这款游戏可以开挂,确实是有挂的,需要了解加客服微信【5848499】很多玩家在这款游戏...
总结文章“新道游棋牌有透视挂吗... 您好:新道游棋牌这款游戏可以开挂,确实是有挂的,需要了解加客服微信【7682267】很多玩家在这款游...
终于懂了手机麻将到底有没有挂... 您好:手机麻将这款游戏可以开挂,确实是有挂的,需要了解加客服微信【8435338】很多玩家在这款游戏...