线程(一)

1. 什么是进程

电脑中的软件

QQ 微信 内网通等启动起来后都是进程

需要占用内存 磁盘 等

1.1 进程的特性

1.独立性

各个进程之间是相互的独立的互不影响 的。录屏软件和idea没有关系的

自我看法: 每个程序都是独立存在的互相没有关联的 一个进程关闭不影响另一个进程运行

2.互斥性

每个软件系统都会分配一个独立端口号,如果启动一个软件以后他的端口号97。

如果再启动另外一个软件,另外一个软件如果端口也是97,这个程序就启动不了,端口被占用的

自我看法: 每个进程端口号都是唯一的 如果有两个端口号相同 一个启动后 另一个再启动 这个进程是无法启动的 因为端口被占用

2. 什么是线程

线程是看不到的 是进程下存在的东西

java程序中一个进程就是一个Demo 每个进程至少有两个线程

一个main主线程 一个jvm垃圾回收线程

2.1 线程的特性

1.抢占式运行【重要】

CPU在执行的时候,按照时间片来执行的,单位的时间片是抢占是执行

比如 idea qq 抢占CPU的,比如qq的线程抢到cpu,idea线程等待

我是一个cpu。你们问我问题。75个线程。同时来问我问题吗?不是

抢着问。一个问。然后其他人等待。这个人甚至还没有问完,其他的某一个人

2.资源共享性

一个线程可以共享当前CPU, 网卡等

3. 线程和进程的区别【面试题】

进程是一个应用程序,是独立的
线程是进程中最小的基本单位。
把进程比作生产车间,每个流水线就是一个线程
进程有独立性和互斥性
线程有抢占式资源共享特性

4. 并发和并行

并发:同时发生 轮流交替进行

并行:同时执行

比如:

你去饭店点了两个菜,生活中拿个筷子轮流夹菜哦这就是并发场景

端起盘子,同时倒到嘴里面,这就是并行场景

5. 创建线程的两种方式【重要】

5.1 Thread类
首先创建类继承Thread类
class A extends Thread {

}
然后重写Thread中run方法
   @Override
   public void run() {
       sout(****);
  }
在main主函数开启进程
A a = new A();
a.start();

语法格式

class A extends Thread {
@Override
   public void run() {
       sout(****);
  }
}
class ... {
  ... main(){
       A a = new A();
       a.start();
  }
}
package com.day22_w.a_Thread;

class MeThread1 extends Thread {
   @Override
   public void run() {
       for (int i = 0; i < 100; i++) {
           System.out.println("吃水煮肉片" + i);
      }
  }
}

class MeThread2 extends Thread {
   @Override
   public void run() {
       for (int i = 0; i < 100; i++) {
           System.out.println("吃毛血旺" + i);
      }
  }
}

public class Demo2 {
   public static void main(String[] args) {
       MeThread1 meThread1 = new MeThread1();
       MeThread2 meThread2 = new MeThread2();
       meThread1.start();
       meThread2.start();
       for (int i = 0; i < 100; i++) {
           System.out.println("吃大盘鸡" + i);
      }
  }
}
5.2 Runnable接口【常用】
首先创建一个类实现Runnable接口
Class B implements Runnable {

}
重写Runnable接口中run抽象方法
   @Override
   public void run() {
       sout(***);
  }
}
然后再main主函数开启线程
   B b = new B();
   Thread thread = new Thread(b);
   thread.start;
   //new Thread(new B()).start;
Class B implements Runnable {
   @Override
   public void run() {
       sout(***);
  }
}
calss ... {
  ... main(){
       B b = new B();
       Thread thread = new Thread(b);
       thread.start;
       //new Thread(new B()).start;
  }
}
package com.day22_w.a_Thread;

class Eat1 implements Runnable {
   @Override
   public void run() {
       for (int i = 0; i < 100; i++) {
           System.out.println("吃水煮肉片 " + i);
      }
  }
}
class Eat2 implements Runnable {
   @Override
   public void run() {
       for (int i = 0; i < 100; i++) {
           System.out.println("吃毛血旺 " + i);
      }
  }
}
public class Demo4 {
   public static void main(String[] args) {
       Eat1 eat1 = new Eat1();
       Eat2 eat2 = new Eat2();
       Thread thread1 = new Thread(eat1);
       Thread thread2 = new Thread(eat2);
       thread1.start();
       thread2.start();
       for (int i = 0; i < 100; i++) {
           System.out.println("吃大盘鸡 " + i);
      }
  }
}

6. 线程下的几个方法

6.1 构造方法
构造方法
Thread() 无参构造 分配一个新的线程
Thread(Runnable target, String name) 分配一个新的线程 并起名
6.2 线程方法
线程方法
String currentThread(); 获取当前线程对象
void setName; 给当前线程起名
Stirng getName; 获取当前线程名称
void setPriority; 给当前线程设置优先级 默认优先级为5
int getPriority; 获取当前线程优先级
static void sleep; `使当前正在执行的线程以指定的毫秒数暂停
package com.day22_w.b_ThreadFun;

class MyThread implements Runnable {

   @Override
   public void run() {
       Thread thread = Thread.currentThread();
       thread.setName("MyThread线程");
       System.out.println(thread.getName());
  }
}

class MyThread1 implements Runnable {

   @Override
   public void run() {
       Thread thread = Thread.currentThread();
       thread.setName("MyThread1线程");
       System.out.println(thread.getName());
  }
}
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();

       //getName() 返回次线程名字
       //java中主线程叫main 子线程叫Thread-0 或Thread-1 ......

       //setName() 设置名字
       //给主线程设置名字
       thread.setName("main主线程");
       System.out.println(thread.getName());
       new Thread(new MyThread()).start();
       new Thread(new MyThread1()).start();

       //Thread(线程对象,name) 分配一个新对象 并起一个名字
       MyThread2 myThread2 = new MyThread2();
       Thread thread1 = new Thread(myThread2,"狗蛋");
       thread1.start();

  }
}
package com.day22_w.b_ThreadFun;

class MyThread3 implements Runnable {

   @Override
   public void run() {
       Thread thread = Thread.currentThread();
       thread.setPriority(10);
       System.out.println(thread.getPriority());
       for (int i = 0; i < 100; i++) {
           System.out.println("子线程3 " + i);
      }
  }
}

class MyThread4 implements Runnable {

   @Override
   public void run() {
       Thread thread = Thread.currentThread();
       thread.setPriority(1);
       System.out.println(thread.getPriority());
       for (int i = 0; i < 100; i++) {
           System.out.println("子线程4 " + i);
      }
  }
}

public class Demo2 {
   public static void main(String[] args) {
       Thread thread = Thread.currentThread();

       //setPriority() 设置优先级
       //所以优先级不要用!!! 并不一定真正优先
       //线程结果是不可控的
       thread.setPriority(1);

       //getPriority() 获取优先级
       System.out.println(thread.getPriority());


//       for (int i = 0; i < 100; i++) {
//           System.out.println("主线程 " + i);
//       }
       new Thread(new MyThread3()).start();
       new Thread(new MyThread4()).start();

  }
}
package com.day22_w.b_ThreadFun;

class MyThread5 implements Runnable {

   @Override
   public void run() {
       try {
           //Thread.sleep(int time) 让线程睡一会

           //发现Thread.sleep()有一个异常
           //但是没有抛出 只有try-catch
           //因为run()是重写的 父类没有抛出 子类就不能抛出
           Thread.sleep(1000);
      } catch (InterruptedException e) {
           e.printStackTrace();
      }
       for (int i = 0; i < 100; i++) {
           System.out.println("MyThread5 " + i);
      }
  }
}

class MyThread6 implements Runnable {

   @Override
   public void run() {
       for (int i = 0; i < 100; 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();

  }
}

7. 线程的同步和锁【重要】

为什么要进行线程的同步?

Java是允许多线程(多个线程),当多个线程操作同一个资源(咋操作)的时候,会导致得到或者打印的数据不准确。从而发生冲突。咋解决?加同步锁。

1

美团
淘票票
这个两个线程,都去麦同一场次的票
结果美团卖出去一张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票

  }
}

线程就是这样,不可控制,但是可以加锁。让他可控制。

posted @   早睡晚起身体好  阅读(53)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
点击右上角即可分享
微信分享提示