快速掌握多线程的相关知识1Java

3.2 多线程

3.2.1.并发问题?

既然CPU同一时刻只能执行一个线程,为什么存在并发问题?

  • CPU的时间是按时间片分的,而不是一个时间点,并发问题是由于CPU根据线程调度算法,进行线程切换导致的。
  • 一段时间内,CPU根据时间分片,执行了不同的线程,可以理解为并发工作。
  • 多线程工作时,容易产生问题。

3.2.2.线程调度算法

  • 分时调度:所有线程轮流使用 CPU 的使用权,平均分配每个线程占用 CPU 的时间。
  • 抢占式调度:优先让优先级高的线程使用 CPU,如果线程的优先级相同,那么会随机选择一个(线程随机性),Java使用的为抢占式调度

3.2.3.Thread类

构造方法:

public Thread() :分配一个新的线程对象。

public Thread(String name) :分配一个指定名字的新的线程对象。

public Thread(Runnable target):分配一个带有指定目标新的线程对象。

public Thread(Runnable target,String name):分配一个带有指定目标新的线程对象并指定名字。

常用方法:

public String getName() :获取当前线程名称。

public void start() :导致此线程开始执行; Java虚拟机调用此线程的run方法。

public void run():此线程要执行的任务在此处定义代码。

public static void sleep(long millis):使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行)。

public static Thread currentThread():返回对当前正在执行的线程对象的引用。

翻阅API后得知创建线程的方式总共有两种,一种是继承Thread类方式,一种是实现Runnable接口方式

3.2.4.创建多线程1:继承Thread

Java中通过继承Thread类来创建并创建启动多线程

  • 1定义java.lang.Thread类的子类,并重写该类的run()方法,该run()方法的方法体就代表了线程需要完成的任务,因此把 run()方法称为线程执行体。

  • 2创建Thread子类的实例,即创建了线程对象

  • 3调用线程对象的start()方法来启动该线程

public class MyThread  extends Thread{
    public MyThread(String name){
      //调用父类的构造方法,指定线程名称。
        super(name);
    }
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(getName()+"正在执行:"+i);
            
        }
    }  
}
--------------------------------------------------------------------------------------
public class MyThreadTest1 {
    public static void main(String[] args) {
        MyThread mt = new MyThread("新线程");
         //开启新线程
        mt.start();
        //在主方法中执行for循环
        for (int i = 0; i < 100; i++) { System.out.println("main线程!"+i); }
    }
}

3.2.5 创建多线程2:Runnable接口

public class MyRunnable  implements Runnable{
    //定义Runnable接口的实现类,该run()方法的方法体同样是该线程的线程执行体。
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName()+":"+i);
        }
    }
}
--------------------------------------------------------------------------------------
  public class MyRunnableTest{
    public static void main(String[] args) {
        //创建Runnable接口的实现类,并重写该接口的run()方法,
        MyRunnable mr = new MyRunnable();
        //创建新线程对象
        Thread new_thread = new Thread(mr, "新线程");
        new_thread.start();
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName()+i);
        }
    }
}
  • 使用匿名内部类简化代码
public class NoNameInnerClassThread {
    public static void main(String[] args) {
        //1.使用匿名内部类的方式开启多线程,作为线程的执行体
        Runnable r = new Runnable(){
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    System.out.println(Thread.currentThread().getName() + i);
                }
            }
        };
        //2.定义线程类。
        new Thread(r,"新线程").start();
        System.out.println("主线程main");
        
        /*//其它方法
        new Thread(new Runnable(){
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    System.out.println(Thread.currentThread().getName() + i);
                }
            }
        },"新线程").start();*/
    }
}

为什么在 Java 中需要内部类?总结一下主要有以下四点:

1.每个内部类都能独立的继承一个接口的实现,所以无论外部类是否已经继承了某个(接口的)实现,对于内部类都没有影响。内部类使得多继承的解决方案变得完整

2.方便将存在一定逻辑关系的类组织在一起,又可以对外界隐藏。

3.方便编写事件驱动程序。

4.方便编写线程代码。

3.2.6 Java的线程同步机制

  • 为保证每个线程都能正常执行原子操作,Java引入了线程同步机制。

    1. 同步代码块。

      Object lock = new Object();
      synchronized(同步锁){ 
      		//需要同步操作的代码 
      } 
      

      注意:在任何时候,最多允许一个线程拥有同步锁,谁拿到锁就进入代码块,其他的线程只能在外等着 (BLOCKED)。

    2. 同步方法。

      public synchronized void method(){ 可能会产生线程安全问题的代码 }
      
    3. 锁机制:

      • java.util.concurrent.locks.Lock机制提供了比synchronized代码块和synchronized方法更广泛的锁定操作
      public void lock() :加同步锁。 
      public void unlock() :释放同步锁。
      ------------------------------------------:lock();
      	//代码块
      	unlock();
      

3.2.7 等待与唤醒机制

  • 保证线程间通信有效的利用资源。
	synchronized(ob){
    ...
    ob.wait();  // 线程进入永久等待
    ...
    ob.notify();  //唤醒使用同一个锁对象的另一个线程(正在因为ob.wait()进入永久等待的线程。)
  }

3.2.8 线程工厂类

线程池测试类:

  public class ThreadPoolDemo {
    public static void main(String[] args) {
  	  // 线程工厂类:Executors的静态方法,创建线程池ExecutorService对象
	    ExecutorService service = Executors.newFixedThreadPool(2);//包含2个线程对象
      // 创建Runnable实例对象
      MyRunnable r = new MyRunnable();
	    // 再获取个线程对象,调用MyRunnable中的run()
  	  service.submit(r);
    	// 注意:submit方法调用结束后,程序并不终止,是因为线程池控制了线程的关闭。
    	// 将使用完的线程又归还到了线程池中
    	// 关闭线程池
    	//service.shutdown();
}

3.2.9 Lambd表达式

  • 函数式编程思想

  • JDK1.8的新特性

    例子:对一个Person对象数组进行排序,

    用到Arrays.sort(arr,comp) , comp 为Comparator 比较器接口的 实现类对象

    import java.util.Arrays;
    import java.util.Comparator;
    
    public class Demo06Comparator {
        public static void main(String[] args) {
          	// 本来年龄乱序的对象数组
            Person[] array = {
            	new Person("古力娜扎", 19),
           		new Person("马尔扎哈", 20) };
          	// 匿名内部类
          --------------------------------------------------------------------
            Comparator<Person> comp = new Comparator<Person>() {   //匿名内部类写法
                @Override
                public int compare(Person o1, Person o2) {
                    return o1.getAge() - o2.getAge(); }
            };
            Arrays.sort(array, comp); // 第二个参数为排序规则,即Comparator接口实例
          --------------------------------------------------------------------
    				Arrays.sort(array, (Person a, Person b)> {  
              	return a.getAge() ‐ b.getAge(); 
            });    //Lambda写法,已知Comparator接口有且仅有一个抽象方法。
          --------------------------------------------------------------------
            for (Person person : array) {
                System.out.println(person);
            }
        }
    }
    

备注:有且仅有一个抽象方法的接口,称为“函数式接口”。

3.2.10线程的6种状态

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值