当前位置: 首页> 教育> 大学 > 莱芜金点子信息港房产网_进销存软件排行榜前十名_网络推广费计入什么科目_seo1域名查询

莱芜金点子信息港房产网_进销存软件排行榜前十名_网络推广费计入什么科目_seo1域名查询

时间:2025/7/11 18:16:11来源:https://blog.csdn.net/weixin_47510148/article/details/144146812 浏览次数:0次
莱芜金点子信息港房产网_进销存软件排行榜前十名_网络推广费计入什么科目_seo1域名查询

“多线程”:并发

要介绍线程,首先要区分开程序、进程和线程这三者的区别。

程序:具有一定功能的代码的集合,但是是静态的,没有启动运行
进程:启动运行的程序【资源的分配单位】
线程:进程中的每一条执行路径,就是线程。

概念
并行:多个CPU同时执行多个任务
并发:一个CPU“同时”执行多个任务(采用时间片切换)

将1分钟---分成10000份=6毫秒

5.1使用线程的3种方式:

第一种方式:继承父类

1.创建线程类:
public class NumberThread extends Thread
2.创建线程对象:【新生状态】
NumberThread num=new NumberThread();
3.【就绪状态】--->cpu给资源--->运行状态
num.start();
如果调用run(),则不是多线程的了,会直接执行完

例子:售票窗口
有10张车票,3个窗口,同时售票,显示售票结果。

package thread;  public class WindowThread extends Thread {  static int ticket=10;  public WindowThread() {  }  public WindowThread(String name) {  super(name);  }  @Override  public void run() {  while (ticket >= 1) {  System.out.println(getName()+"窗口,卖出第"+ticket+"票");  ticket--;  }  }  
}
package thread;  public class TestMain {  public static void main(String[] args) {  WindowThread w1=new WindowThread("第1");  w1.start();  WindowThread w2=new WindowThread("第2");  w2.start();  WindowThread w3=new WindowThread("第3");  w3.start();  }
}

在这里插入图片描述

优点:启动线程对象高效率
缺点:占用了父类位置

第二种方式:实现接口

public class Window implements Runnable {  int ticket=10;  @Override  public void run() {  while (ticket >= 1) {  System.out.println(Thread.currentThread().getName()+"窗口卖出第"+ticket+"张票");  ticket--;  }  }  
}
public class Test {  public static void main(String[] args) {  Window w1=new Window();  Thread t1 = new Thread(w1,"第1");  t1.start();  Thread t2 = new Thread(w1, "第2");  t2.start();  Thread t3 = new Thread(w1, "第3");  t3.start();  }  
}

优点:没有占用父类位置,共享资源能力强,资源不用加static
缺点:启动线程对象 效率低

第三种方式:实现接口

对比第一种和第二种创建线程的方式发现,无论第一种继承Thread类的方式还是第二种实现Runnable接口的方式,都需要有一个run方法
但是这个run方法有不足:

在这里插入图片描述

1)没有返回值
2)不能抛出异常

基于上面的两个不足,在JDK1.5以后出现了第三种创建线程的方式:实现Callable接口:

实现Callable接口好处:(1)有返回值 (2)能抛出异常
缺点:线程创建比较麻烦

package com.msb.test05;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
/*** @author : msb-zhaoss*/
public class TestRandomNum implements Callable<Integer> {/*1.实现Callable接口,可以不带泛型,如果不带泛型,那么call方式的返回值就是Object类型2.如果带泛型,那么call的返回值就是泛型对应的类型3.从call方法看到:方法有返回值,可以跑出异常*/@Overridepublic Integer call() throws Exception {return new Random().nextInt(10);//返回10以内的随机数}
}
class Test{//这是main方法,程序的入口public static void main(String[] args) throws ExecutionException, InterruptedException {//定义一个线程对象:TestRandomNum trn = new TestRandomNum();FutureTask ft = new FutureTask(trn);Thread t = new Thread(ft);t.start();//获取线程得到的返回值:Object obj = ft.get();System.out.println(obj);}
}

FutureTaskRunnable接口的一个实现类,因此它可以作为参数传给Tread
用线程任务对象来接返回值(这里用的是ft)
注意:get方法的使用位置必须在start之后
创建几个线程对象,就要创建几个FutreTask,而不能new两个Thread,因为这样是一个对象的内容接了两遍

5.2线程对象的常用方法:

  • a.getName()获得当前线程对象的名字:
    ---线程名 如果开发者使用了无参构造器,程序自动设置线程名Thread-0++(主线程除外)
    ---开发者使用有参构造器,参数的值就是线程的名字。
public class NumberThread extends Thread{  public NumberThread() {  }  public NumberThread(String name) {  super(name);  }  @Override  public void run() {    //第二条执行路线的内容  for (int i = 1; i < 100; i++) {  System.out.println(super.getName()+"i="+i);   //获得当前线程名  }  }  
}

---借助num.setName("线程1"),为线程名赋值

public class TestMain {  //main()方法所在的线程叫主线程  public static void main(String[] args) {  NumberThread num=new NumberThread("窗口1");  //此时程序开启第二条路  num.start();  NumberThread num2=new NumberThread("窗口2");  //此时程序开启第二条路  num2.start();  for (int i = 1; i < 100; i++) {  System.out.println(Thread.currentThread().getName()+"i="+i);  }  }  
}
  • b.currentThread()获得当前正在运行的线程对象
    针对实现接口的情况,由于没有再继承Thread类,因此也无法直接使用其中的方法getName(),但Thread类中有静态方法currentThread(),因此可以通过这种方法获得当前运行的线程对象的信息。
  • c.setPriority()设置线程的优先级,1-10之间,默认是5
Thread t2 = new Thread(w1, "第2");  
t2.setPriority(1);  //设置线程的优先级,1-10之间,默认是5  
t2.start();
  • d.Thread.currentThread().stop() 过期方法,不建议执行
  • e.强行占用。当一个线程调用了join方法,这个线程就会先被执行,它执行结束以后才可以去执行其余的线程。
public static void main(String[] args) throws InterruptedException {  NumberThread num=new NumberThread("窗口1");  //此时程序开启第二条路  num.start();  for (int i = 1; i < 100; i++) {  System.out.println(Thread.currentThread().getName()+"i="+i);  if (i == 50) {  num.join();  //强势加入(num运行完了后,其余的才能执行)System.out.println("maini=50");  }  }  
}
  • f.setDaemon(true);伴随线程
    tt.setDaemon(true);//设置伴随线程
    主线程死亡,伴随线程也会跟着一起死亡。
public class TestThread extends Thread {@Overridepublic void run() {for (int i = 1; i <= 1000 ; i++) {System.out.println("子线程----"+i);}}
}
class Test{//这是main方法,程序的入口public static void main(String[] args) {//创建并启动子线程:TestThread tt = new TestThread();tt.setDaemon(true);//设置伴随线程  注意:先设置,再启动tt.start();//主线程中还要输出1-10的数字:for (int i = 1; i <= 10 ; i++) {System.out.println("main---"+i);}}
}
  • g.sleep(毫秒):设置线程休眠
public static void main(String[] args) throws InterruptedException {  System.out.println("1111");  Thread.sleep(1000);  //休眠的例子System.out.println("222");  
}

5.3线程的生命周期:

使用线程构造器---创建线程对象--->线程新生状态
创建线程对象.start()--->进入到就绪状态【有资格,没资源】
线程对象.run()--->进入到运行状态【有资格,有资源】

在时间片段内,执行完--->死亡状态
在时间片段内,没执行完--->重回就绪状态
在时间片段内,出现突发事件--->阻塞状态--->就绪状态

在这里插入图片描述

5.4解决线程安全问题:

【第一种:同步代码块】

public void run() {  while (true) {  synchronized (WindowThread.class){ //WindowThread.class是监视器对象  if(ticket >= 1) {  System.out.println(getName() + "窗口,卖出第" + ticket + "票");  ticket--;  }  }  }  
}

总结:
同步监视器总结:
1:认识同步监视器(锁子) ----- synchronized(同步监视器){ }
1)必须是引用数据类型,不能是基本数据类型
2)也可以创建一个专门的同步监视器,没有任何业务含义
3)一般使用共享资源做同步监视器即可
4)在同步代码块中不能改变同步监视器对象的引用
5)尽量不要String和包装类Integer做同步监视器
6)建议使用final修饰同步监视器

2:同步代码块的执行过程
1)第一个线程来到同步代码块,发现同步监视器open状态,需要close,然后执行其中的代码
2)第一个线程执行过程中,发生了线程切换(阻塞 就绪),第一个线程失去了cpu,但是没有开锁open
3)第二个线程获取了cpu,来到了同步代码块,发现同步监视器close状态,无法执行其中的代码,第二个线程也进入阻塞状态
4)第一个线程再次获取CPU,接着执行后续的代码;同步代码块执行完毕,释放锁open
5)第二个线程也再次获取cpu,来到了同步代码块,发现同步监视器open状态,拿到锁并且上锁,由阻塞状态进入就绪状态,再进入运行状态,重复第一个线程的处理过程(加锁)
强调:同步代码块中能发生CPU的切换吗?能!!! 但是后续的被执行的线程也无法执行同步代码块(因为锁仍旧close)

3:其他
1)多个代码块使用了同一个同步监视器(锁),锁住一个代码块的同时,也锁住所有使用该锁的所有代码块,其他线程无法访问其中的任何一个代码块
2)多个代码块使用了同一个同步监视器(锁),锁住一个代码块的同时,也锁住所有使用该锁的所有代码块, 但是没有锁住使用其他同步监视器的代码块,其他线程有机会访问其他同步监视器的代码块

【第二种:同步方法】

public class WindowThread extends Thread {  static int ticket = 300;  public WindowThread() {  }  public WindowThread(String name) {  super(name);  }
@Override  
public void run() {  while (true) {  if (ticket == 0) {  break;  } else {  buyTicket();  }   }  
}  public static synchronized void buyTicket(){   
//如果只有synchronized,锁住的只是当前this对象(相当于每一个都有300张票)
//如果加了static,锁住的就是方法。if(ticket >= 1) {  System.out.println(Thread.currentThread().getName() + "窗口,卖出第" + ticket + "票");  ticket--;  }  }
}

总结:
1:
多线程在争抢资源,就要实现线程的同步(就要进行加锁,并且这个锁必须是共享的,必须是唯一的。
咱们的锁一般都是引用数据类型的。
目的:解决了线程安全问题。

2:关于同步方法

  1. 不要将run()定义为同步方法
  2. 非静态同步方法的同步监视器是this
    静态同步方法的同步监视器是 类名.class 字节码信息对象
  3. 同步代码块的效率要高于同步方法
    原因:同步方法是将线程挡在了方法的外部,而同步代码块锁将线程挡在了代码块的外部,但是却是方法的内部
  4. 同步方法的锁是this,一旦锁住一个方法,就锁住了所有的同步方法;同步代码块只是锁住使用该同步监视器的代码块,而没有锁住使用其他监视器的代码块
    【第三种方式:Lock锁】
@Override  //Lock锁  
public void run() {  Lock lock = new ReentrantLock();  //创建Lock锁对象  while (true) {  lock.lock();//上锁  if (ticket >= 1) {  System.out.println(getName() + "窗口,卖出第" + ticket + "票");  ticket--;  }  lock.unlock();  //解锁  if (ticket == 0) {  break;  }  }  
}

5.5线程通信:

在这里插入图片描述

package com.msb.test11;
/*** @author : msb-zhaoss*/
public class Product {//商品类//品牌private String brand;//名字private String name;//引入一个灯:true:红色  false 绿色boolean flag = false;//默认情况下没有商品 让生产者先生产  然后消费者再消费//setter,getter方法;public String getBrand() {return brand;}public void setBrand(String brand) {this.brand = brand;}public String getName() {return name;}public void setName(String name) {this.name = name;}//生产商品public synchronized void setProduct(String brand,String name){if(flag == true){//灯是红色,证明有商品,生产者不生产,等着消费者消费try {wait();} catch (InterruptedException e) {e.printStackTrace();}}//灯是绿色的,就生产:this.setBrand(brand);try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}this.setName(name);//将生产信息做一个打印:System.out.println("生产者生产了:" + this.getBrand() + "---" + this.getName());//生产完以后,灯变色:变成红色:flag = true;//告诉消费者赶紧来消费:notify();}//消费商品:public synchronized void getProduct(){if(!flag){//flag == false没有商品,等待生产者生产:try {wait();} catch (InterruptedException e) {e.printStackTrace();}}//有商品,消费:System.out.println("消费者消费了:" + this.getBrand() + "---" + this.getName());//消费完:灯变色:flag = false;//通知生产者生产:notify();}
}
关键字:莱芜金点子信息港房产网_进销存软件排行榜前十名_网络推广费计入什么科目_seo1域名查询

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: