java学习--day22(进程线程)
- 软件开发
- 2025-08-17 14:12:03

文章目录 1.什么是进程2.什么是线程3.线程和进程的区别【面试题】4.并发和并行5.创建线程的两种方式【重点】1.继承Thread2.实现Runnable接口 6.线程下面的几个方法7.线程的同步和锁【重要】 1.什么是进程
是独立的运行程序
比如咱们电脑软件,你启动起来以后,他就是一个进程。qq idea
进程需要windows系统的分配。可以获取当前的系统的网卡,内存,显卡等
1.独立性
各个进程之间是相互的独立的互不影响 的。录屏软件和idea没有关系的
2.互斥性
每个软件系统都会分配一个独立端口号,如果启动一个软件以后他的端口号97。
如果再启动另外一个软件,另外一个软件如果端口也是97,这个程序就启动不了,端口被占用的
脑海里面知道开启的软件就是一个进程 即可!!!
2.什么是线程进程是由多个或者一个线程组成的。每个进程至少得有一个线程的支撑。
脑海里面这样来想,一个进程(qq),qq里面很多个线程在执行。线程的执行
支撑起来了进程的执行。
把一个人比作一个进程,那么你身体里面的细胞就是线程。如果没有细胞。这个人还存在吗?不存在的!!!
进程包含了线程,线程是组成进程的最小基本单位
特性:
1.抢占式运行的【重要】
CPU在执行的时候,按照时间片来执行的,单位的时间片是抢占是执行
比如 idea qq 抢占CPU的,比如qq的线程抢到cpu,idea线程等待
我是一个cpu。你们问我问题。75个线程。同时来问我问题吗?不是
抢着问。一个问。然后其他人等待。这个人甚至还没有问完,其他的某一个人
抢到我了,他问我。大概就是效果
2.资源共享性
一个线程可以共享当前CPU, 网卡等
Java程序:
一个Java程序就是一个进程 Demo1 就是一个应用程序 就是一个进程
一个Java程序Demo1里面至少 几个线程?
两个:
main主函数线程
JVM垃圾回收器线程
3.线程和进程的区别【面试题】 进程是一个应用程序,是独立的 线程是进程中最小的基本单位。 把进程比作生产车间,每个流水线就是一个线程 进程有独立性和互斥性 线程有抢占式资源共享特性 4.并发和并行并发:同时发生,轮流交替执行
并行:真正意义的同时执行
比如:
你去饭店点了两个菜,生活中拿个筷子轮流夹菜哦这就是并发场景
端起盘子,同时倒到嘴里面,这就是并行场景
5.创建线程的两种方式【重点】 1.继承Thread创建线程的两种方式
一个是将一个类声明为Thread的子类。 这个子类应该重写run方法 。 然后可以分配并启动子类的实例。 package com.qfedu.a_thread; // 一个是将一个类声明为Thread的子类。 // 这个子类应该重写run类的方法Thread 。 // 然后可以分配并启动子类的实例。 class MyThread1 extends Thread{ @Override public void run() { for (int i = 0; i < 500; i++) { System.out.println("我是myThread1线程:" + i); } } } class MyThread2 extends Thread { @Override public void run() {//run方法中写功能代码 就是一个线程中执行的一个功能 for (int i = 0; i < 500; i++) { System.out.println("我是mythread2线程:" + i); } } } public class Demo1 { public static void main(String[] args) { //官方手册中说,要去实例化Thread的子类,并启动线程 MyThread1 myThread1 = new MyThread1(); //启动线程 使用start方法 在主线程中开启子线程 myThread1.start(); MyThread2 myThread2 = new MyThread2(); myThread2.start(); //现在有几个线程? 3个 //一个是MyThread1线程 一个是主线程(main) 一个垃圾回收机制线程 for (int i = 0; i < 500; i++) { System.out.println("主函数线程:" + i); } //发现先执行了主线程,然后再执行子线程,然后又执行主线程 //这就线程的抢占式的运行 //三个线程: //你自己吃三盘菜,咋吃? //一盘菜代表一个线程,一盘菜夹一下,随机的吧。 //开启一个线程,就是在执行一个任务。 //上面这个代码,你们执行结果和我执行的结果一样吗?绝对不一样的 //抢占式的,随机执行线程的!!! } } 练习: main主线程 打印100遍的吃大盘鸡 子线程1 打印100遍的吃水煮肉片 子线程2 打印100遍的吃毛血旺 一定要注意打印的结果,多执行几遍,看看每次执行的结果是否一样!!! 2.实现Runnable接口另一种方法来创建一个线程是声明实现类Runnable接口。 那个类然后实现了run方法。 然后可以分配类的实例,在创建Thread时作为参数传递,并启动。
package com.qfedu.a_thread; //另一种方法来创建一个线程是声明实现类Runnable接口。 // 那个类然后实现了run方法。 // 然后可以分配类的实例(创建类的对象),在创建Thread实例时作为参数传递,并启动。 class MyThread3 implements Runnable { @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println("MyThread3:" + i); } } } class MyaThread4 implements Runnable { @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println("MyThread4:" + i); } } } public class Demo2 { public static void main(String[] args) { MyThread3 myThread3 = new MyThread3(); //Thread(Runnable target) 参数是Runnable这个接口对象 //分配一个新的 Thread对象。 Thread thread = new Thread(myThread3); thread.start(); MyaThread4 myaThread4 = new MyaThread4(); Thread thread1 = new Thread(myaThread4); thread1.start(); for (int i = 0; i < 100; i++) { System.out.println("main主线程:" + i); } //有几个线程做任务的线程 3个 一个是main主线程 一个是MyThread3 //一个MyThread4这个线程 //可以发现运行的结果是随机执行的!!! } } 6.线程下面的几个方法构造方法
Thread()分配一个新的 Thread对象。 无参构造方法Thread(Runnable target)分配一个新的 Thread对象。 有参构造Thread(Runnable target, String name)分配一个新的 Thread对象。并起名字线程方法:
static ThreadcurrentThread()返回对当前正在执行的线程对象的引用StringgetName()返回此线程的名称。voidsetName(String name)将此线程的名称更改为等于参数 name 。intgetPriority()返回此线程的优先级。voidsetPriority(int newPriority)更改此线程的优先级。设置优先并不一定优先,只是增加了执行的概率。最小值是1,最大值是10,默认的是5static voidsleep(long millis)使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行),具体取决于系统定时器和调度程序的精度和准确性。 package com.qfedu.b_threadfun; class MyThread1 implements Runnable { @Override public void run() { Thread thread = Thread.currentThread(); //此时这个thread对象是MyThread1这个线程 //对子线程设置名字 thread.setName("mythread1子线程"); System.out.println(thread.getName());//Thread-0 } } class MyThread2 implements Runnable { @Override public void run() { Thread thread = Thread.currentThread(); System.out.println(thread.getName());//狗蛋 } } public class Demo1 { public static void main(String[] args) { //currentThread() 获取当前线程对象 Thread thread = Thread.currentThread(); //现在thread 这个对象是哪个线程?主线程 //为啥是main主线程 //给main主线程设置名字 thread.setName("主线程"); //获取的是main主线程的名字,Jvm会给主线程还有其他线程一个默认的名字 System.out.println(thread.getName());//main // MyThread1 myThread1 = new MyThread1(); // Thread thread1 = new Thread( myThread1); // thread1.start(); new Thread(new MyThread1()).start(); //Java中默认的主线程叫main 子线程叫Thread-0 Thread-1.... //默认的有名字,咱们能不能对线程自定义名字?能 //我在启动MyThread2的这个线程的时候顺便起名字 MyThread2 myThread2 = new MyThread2(); //myThread2线程的名字就叫狗蛋,是在创建线程的时候就已经起好名字了 Thread thread1 = new Thread(myThread2, "狗蛋"); thread1.start(); } } package com.qfedu.b_threadfun; class MyThread3 implements Runnable { @Override public void run() { //想看一下MyThread3这个线程的优先级是几 Thread thread = Thread.currentThread(); thread.setPriority(10); System.out.println(thread.getPriority()); for (int i = 0; i < 100; i++) { System.out.println("MyThread3线程:" + i); } } } class MyThread4 implements Runnable { @Override public void run() { //想看一下MyThread3这个线程的优先级是几 Thread thread = Thread.currentThread(); thread.setPriority(1); System.out.println(thread.getPriority()); for (int i = 0; i < 100; i++) { System.out.println("MyThread4线程:" + i); } } } public class Demo2 { public static void main(String[] args) { //默认的优先级都是5,能不能手动去修改某一个线程的优先级? //可以 Thread thread = Thread.currentThread(); //主线程的优先级设置1 //thread.setPriority(1); //获取主线程的优先级 System.out.println(thread.getPriority());//5 //优先级 1 ~10 1的优先级最低 10的优先级最高 //jvm默认线程的优先级是5 // for (int i = 0; i < 100; i++) { // System.out.println("主线程:" + i); // } new Thread(new MyThread3()).start(); new Thread(new MyThread4()).start(); //所以优先级不要用啦!!!并不一定真正的优先!!! //线程执行的结果不可控!!!很尴尬!!! } } package com.qfedu.b_threadfun; class MyThread5 implements Runnable { @Override public void run() { try { //发现 Thread.sleep 有一个运行时异常, //但是发现没有抛出,只有try-catch 为啥? //sleep方法写在了run方法中了,因为 //run方法是重写的, 父类的 public abstract void run(); //父类有抛出吗?没有抛出,重写是比较严格的 //父类没有抛出,子类也同样不能抛出 Thread.sleep(10000);//10秒 } catch (InterruptedException e) { e.printStackTrace(); } for (int i = 0; i < 500; i++) { System.out.println("MyThread5:" + i); } } } class MyThread6 implements Runnable { @Override public void run() { for (int i = 0; i < 500; i++) { System.out.println("MyThread6:" + i); } } } public class Demo3 { public static void main(String[] args) { new Thread(new MyThread5()).start(); new Thread(new MyThread6()).start(); //发现运行的结果是不可控的,是随机的抢占式的 //咱们接下来学习一个东西叫sleep 让某一个线程睡一会儿 //这个线程在睡觉的期间不会去抢占cpu 不执行 //现在我让MyTread5睡了一会儿。就意味着绝对MyThread6线程先执行 //实现可控的效果 //思考:sleep方法再开发的时候敢用不敢用? //不敢用。睡多久你知道吗?睡多久合适?不能确定 //cpu最大利用化。不可能让cpu闲置 //如果sleep睡眠时间少的话,还是抢占 //如果sleep睡眠你时间太长的话,就会cpu就会闲置 //没有办法把控的!!! 接下来要学习锁!!! } }回顾:
1.新建线程的两种方式 1.继承Thread 2.实现Runnable接口【开发要用的】 代码要自己学会写的!!! 2.线程的方法 Thread.currentThread();获取当前线程对象 setPriority();设置优先级的 getPriority(); 获取当前线程的优先级 getName();得到线程的名字 setName();设置线程的名字 sleep();线程的休眠 7.线程的同步和锁【重要】为什么要进行线程的同步?
Java是允许多线程(多个线程),当多个线程操作同一个资源(咋操作)的时候,会导致得到或者打印的数据不准确。从而发生冲突。咋解决?加同步锁。
美团 淘票票 这个两个线程,都去麦同一场次的票 结果美团卖出去一张1排1列的票 结果淘票票也卖出去了1排1列的票 你感觉合适吗? 就是上面的这种结果!!!不合适的,分享同一个资源的时候,要保证分享资源的数据,合法性!!! 分析结果: package com.qfedu.c_sync; //最理想的状态!!! //先线程1进入到ticket=50,循环 循环结束以后 此时 //tiket=49了 //循环第二次的时候 线程2抢到资源了 此时ticket=49 //循环 打印49 tiket-- ticket=48了 //循环第三次的时候 线程2 抢到资源了, 此时ticket=48 //打印卖第48张票。ticket-- tiket=47 //线程1又抢到循环 //现在的情况是:有可能两个线程同时进入到while循环 // class MySync implements Runnable { int ticket = 50; @Override public void run() { // while (true) {//死循环 //两个线程都进入到了循环了 //此时两个线程所持有的ticket 都是50 //但是两个线程都要往下执行 //有可能线程1 先执行了sout(50) 线程2在等待哦!!! //线程1执行了--操作并出了循环 线程1ticket = 49 //线程1又抢到循环了 sout(49) tiket-- //再进入倒这个循环,有可能线程2抢到这个执行权 //线程2要往下执行输出语句 ticket=50 打印50 if (ticket > 0) { //线程具有抢占式的运行 //咱们有没有可能,线程3进入到if语句 //此时线程1也进入到if语句了 //线程3去打印 卖出了50张票 //在线程1里面 ticket=50 //线程3又抢到ticket-- 又进入到循环了 ticket = 49 //线程3又抢到了ticket-- 又进入倒循环 ticket=48 //线程1又抢到资源要执行,执行输出语句 tiekct=50 System.out.println(Thread.currentThread().getName() + "卖出了第" + ticket + "票"); ticket--; } else { System.out.println("买完了"); break;//终止循环!!! } } } } public class Demo1 { public static void main(String[] args) { MySync mySync = new MySync(); //这三个线程 Thread thread1 = new Thread(mySync, "线程1"); thread1.start(); Thread thread2 = new Thread(mySync, "线程2"); thread2.start(); Thread thread3 = new Thread(mySync, "线程3"); thread3.start(); } }解决方案:
1.同步方法:使用一个关键字synchronized修饰方法。因为Java对象都有一个内置的锁对象。当使用这个关键字的时候,修饰方法的时候,这个方法就会被锁保护起来被锁锁住
当一个线程进来以后,会立马锁住当前的方法。意味着只有一个线程进来,其他线程都在外面等着。
public synchronized void run () { } package com.qfedu.c_sync; //最理想的状态!!! //先线程1进入到ticket=50,循环 循环结束以后 此时 //tiket=49了 //循环第二次的时候 线程2抢到资源了 此时ticket=49 //循环 打印49 tiket-- ticket=48了 //循环第三次的时候 线程2 抢到资源了, 此时ticket=48 //打印卖第48张票。ticket-- tiket=47 //线程1又抢到循环 //现在的情况是:有可能两个线程同时进入到while循环 // class MySync1 implements Runnable { int ticket = 50; //对这个run方法加了锁 就意味着只有一个线程进入到run方法中 //其他线程都在run方法外面等待 @Override public synchronized void run() { // while (true) {//死循环 //两个线程都进入到了循环了 //此时两个线程所持有的ticket 都是50 //但是两个线程都要往下执行 //有可能线程1 先执行了sout(50) 线程2在等待哦!!! //线程1执行了--操作并出了循环 线程1ticket = 49 //线程1又抢到循环了 sout(49) tiket-- //再进入倒这个循环,有可能线程2抢到这个执行权 //线程2要往下执行输出语句 ticket=50 打印50 if (ticket > 0) { //线程具有抢占式的运行 //咱们有没有可能,线程3进入到if语句 //此时线程1也进入到if语句了 //线程3去打印 卖出了50张票 //在线程1里面 ticket=50 //线程3又抢到ticket-- 又进入到循环了 ticket = 49 //线程3又抢到了ticket-- 又进入倒循环 ticket=48 //线程1又抢到资源要执行,执行输出语句 tiekct=50 System.out.println(Thread.currentThread().getName() + "卖出了第" + ticket + "票"); ticket--; } else { System.out.println("买完了"); break;//终止循环!!! } } } } public class Demo2 { public static void main(String[] args) { MySync1 mySync = new MySync1(); //这三个线程 Thread thread1 = new Thread(mySync, "线程1"); thread1.start(); Thread thread2 = new Thread(mySync, "线程2"); thread2.start(); Thread thread3 = new Thread(mySync, "线程3"); thread3.start(); //为啥都是线程1卖出去的票? //很巧 线程1抢到执行权了,进入到run方法中 //线程2和线程3在外面等着。 //一个循环进来以后,把循环全部执行完!!! //会出现一家独大的情况!!!也是不符合咱们生活场景的!!! //咋解决?咱们 不能方法中加锁,在其他地方加锁 } }换另外一种解决方法:
同步代码块:就是拥有了synchronized 关键字修饰一个语句块。被修饰的语句块会被加锁。从而实现同步。
语法格式:
synchronized (this) { 被加锁的代码块 } package com.qfedu.c_sync; //最理想的状态!!! //先线程1进入到ticket=50,循环 循环结束以后 此时 //tiket=49了 //循环第二次的时候 线程2抢到资源了 此时ticket=49 //循环 打印49 tiket-- ticket=48了 //循环第三次的时候 线程2 抢到资源了, 此时ticket=48 //打印卖第48张票。ticket-- tiket=47 //线程1又抢到循环 //现在的情况是:有可能两个线程同时进入到while循环 // class MySync2 implements Runnable { int ticket = 500; //对这个run方法加了锁 就意味着只有一个线程进入到run方法中 //其他线程都在run方法外面等待 @Override public void run() { //能不能对循环加锁?不能 因为循环加锁以后,还是一个线程循环完,没有任何意义 while (true) {//死循环 //if语句加了锁以后 //就意味着只有一个线程进入到if语句 //假如线程1进入if语句了,线程2和线程3就会等待 //线程1打印50 并-- ticket变量为49 //线程2抢到了49 sout(49) tiket-- 48 //其他线程再抢!!! //核心业务 加了锁,只让一个线程进入,操作完以后。锁释放掉 //然后这三个线程再抢。还只能进一个,再操作核心业务 synchronized (this) {//只能让一个线程进入操作,其他线程在外面等待排队 if (ticket > 0) { //线程具有抢占式的运行 //咱们有没有可能,线程3进入到if语句 //此时线程1也进入到if语句了 //线程3去打印 卖出了50张票 //在线程1里面 ticket=50 //线程3又抢到ticket-- 又进入到循环了 ticket = 49 //线程3又抢到了ticket-- 又进入倒循环 ticket=48 //线程1又抢到资源要执行,执行输出语句 tiekct=50 System.out.println(Thread.currentThread().getName() + "卖出了第" + ticket + "票"); ticket--; } else { System.out.println("买完了"); break;//终止循环!!! } } } } } public class Demo3 { public static void main(String[] args) { MySync2 mySync = new MySync2(); //这三个线程 Thread thread1 = new Thread(mySync, "线程1"); thread1.start(); Thread thread2 = new Thread(mySync, "线程2"); thread2.start(); Thread thread3 = new Thread(mySync, "线程3"); thread3.start(); //为啥都是线程1卖出去的票? //很巧 线程1抢到执行权了,进入到run方法中 //线程2和线程3在外面等着。 //一个循环进来以后,把循环全部执行完!!! //会出现一家独大的情况!!!也是不符合咱们生活场景的!!! //咋解决?咱们 不能方法中加锁,在其他地方加锁 } }针对于同步代码块举个例子:
上厕所的时候,有坑位,这个坑位就是资源。
三个人去抢这个资源,如果不加锁的话,会出现问题的?是的。加上锁以后就会保证数据准确性。
案例:
加锁的目的为了保证数据的准确性。 卖电影票: 三个线程: 淘票票 美团 猫眼 100张票 package com.qfedu.c_sync; class SaleTicket implements Runnable { //声明一个变量票 //静态的变量和对象没有关系了 private static int ticket = 100; @Override public void run() { //美团 while (true) { //美团 猫眼 淘票票 synchronized (this) { if (ticket > 0) { //淘票票 和猫眼同时进入到if语句,但是都没有执行ticket--这个操作 System.out.println(Thread.currentThread().getName() + "卖出了第" + ticket + "票"); //所以会打印 淘票票 100 猫眼100 ticket--; } else { System.out.println("卖完了"); break; } } } } } public class Demo4 { public static void main(String[] args) { SaleTicket saleTicket = new SaleTicket(); new Thread(saleTicket, "淘票票").start(); new Thread(saleTicket, "美团").start(); new Thread(saleTicket, "猫眼").start(); //淘票票卖出了第100票 //猫眼卖出了第100票 //淘票票卖出了第99票 //淘票票卖出了第97票 //淘票票卖出了第96票 //淘票票卖出了第100票 //淘票票卖出了第99票 //猫眼卖出了第98票 //猫眼卖出了第97票 } }线程就是这样,不可控制,但是可以加锁。让他可控制。
java学习--day22(进程线程)由讯客互联软件开发栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“java学习--day22(进程线程)”
上一篇
QT位置相关函数
下一篇
objective-c基础学习