多线程的介绍

多线程

1,进程

**概述:**正在运行的程序叫做进程。进程是系统进行资源分配和调用的独立单位,每一个进程都有它自己的内存空间和系统资源。

多进程的意义:
单进程计算机只能做一件事情,而现代计算机都是多进程,也就是可以同时做很多事情。

**举例:**一边记笔记,一边屏幕广播,一边执行代码

所以多进程的意义:同一个时间可以进行多个任务,提高工作效率,并且提高cpu的使用率。

思考:

我电脑是单核处理器,我一边做笔记,一边屏幕广播,它们是同时进行的吗?

一个cpu在一个时间点上,只能做一件事情,它在执行多个进程时进行程序间的高速切换,这个时间非常短。所以给我们的感官是进程同时执行。

2,线程

在同一个进程中,可以执行多个任务,而每一个任务就是一个线程。

概述:

线程也就是程序执行单元。也是执行路径,线程也是程序使用cpu资源的基本单位。

单线程:
只有一条执行路径或一个执行单元

多线程:

有多条执行路径或多个执行单元。

多线程的意义:

1,线程的执行是抢占式的,它要抢占cpu的资源,一个多线程程序在执行时,如果一些线程必须等待的时候,cpu资源就可以交给其他线程去使用,这样就提高了cpu的使用率。

2,对于进程来说,如果它是多线程的,在抢占cpu资源时,就有更大的机率抢占到cpu资源。提高程序的执行率。

3,在抢占cpu资源时,是具有随机性的,我们不敢保证哪一个线程在哪一段时间可以抢到cpu资源。

**注意:**jvm是多线程,一个主线程和一个垃圾回收线程

3,并行,并发

并行:

多个处理器或多个处理器同时处理多个不同任务

某一段时间内运行多个程序

并发:

一个处理器同时处理多个任务

某个时间点运行多个程序

举例:

1,并发就相当于一个人同时吃3个馒头,并行就相当于3个人分别吃1馒头

2,我正在吃饭,突然来电话,但是我直到吃完饭,我才去接电话,就代表我不支持并发,也不支持并行

我正在吃饭,突然来电话,我停止吃饭,去接电话,接完电话,接着吃饭,代表我支持并发

我正在吃饭,突然来电话,我一边吃饭,一边打电话,这就代表我支持并行。

4,如何实现多线程

由于线程是依赖于进程存在的,所以首先我们要创建一个进程,而进程是由系统来创建的,所以我们需要调用系统的某些功能来创建进程,但是java是不能调用系统功能,但是它可以调用c/c++写好的程序来创建进程,进而实现多线程。

Java讲c/c++写好的代码封装到一个类中,然后通过这个类可以直接调用创建进程,线程的这些功能。然后间接的实现多线程。

java提供这个类叫做Thread类

通过API,我们就知道创建线程有两种方式

1,一种方法是将类声明为Thread子类,该子类应重写Thread类的run()方法

2

方式1:

1,自定义线程MyThread,继承Thread

2,MyThread类重写run()方法

3,创建MyThread类对象

4,启动线程Start

**方式2:**1,实现Runnable接口

​ 2,重写run方法

​ 3,创建自定义线程类对象

​ 4,创建Thread对象并将自定义线程对象作为参数进行传递

​ 5,start()

**注意:**直接调用线程对象的run方法相当于普通方法的调用,启动线程要用start方法,用start方法流程是,start先启动线程,然后由jvm去调用run方法

**思考:为什么要重写run方法?

一个类中,我们并不需要所有的方法都按照线程去完成,只需要将要按照线程执行的功能写进run方法就可以了

线程可以被多次启动吗?

不能,线程只能启动一次,如果写调用两次start方法,相当于调用了两次线程,既不是启动了两次线程,也不是开启了两条线程。

/* 创建多线程
* 1.自定义线程MyThread类,继承Thread类
   2.MyThread类重写run()方法,重写的内容就是线程要干的工作
   3.创建MyThread类对象
  4.启动线程start();
  *
  * 线程重命名:1.setName(String name)
  * 2.有参构造;在子类中声名有参构造,并显示指定访问父类有参构造
  *
  * 获取当前执行的线程名:Thread.currentThread().getName()
* */

public class MyThread  extends Thread{
    public MyThread(String name){
        super(name);
    }
    @Override
    public void run() {
        //线程一般用来执行比较耗时间的工作
        for(int i=0;i<500;i++){
            System.out.println(getName()+":"+i);
        }
    }
}
class  MyThreadD{
    public static void main(String[] args) {
        MyThread myThread=new MyThread("holy");
        MyThread myThread1=new MyThread("shit");
//        myThread.setName("holy");
//        myThread1.setName("shit");
      /*  myThread.run();
        myThread1.run();//普通方法调用*/
        myThread.start();//启动线程
        myThread1.start();
        System.out.println(Thread.currentThread().getName());//获取主线程的名称
    }
}

4,1设置线程优先级

两种线程调度模型

1,分时调度:所有线程轮流使用cpu的使用权,平均分配每个线程占用CPU的时间片。

2,抢占式调度:该调度模型会优先让优先级高的线程使用cpu,如果优先级相同,则随机选择,优先级高的线程只代表他抢到cpu的概率较大

**默认优先级为5,优先级最小是1,最大是10 **

public class MyThread1 extends Thread {
    public MyThread1(String name) {
        super(name);
    }

    @Override
    public void run() {
        for(int i=0;i<10;i++){
            System.out.println(getName()+":"+i);
        }
    }
}
class ThreadD2{
    public static void main(String[] args) {
        MyThread1 myThread1=new MyThread1("彭于晏");
        MyThread1 myThread11=new MyThread1("金城武");
        myThread1.setPriority(4);//设置优先级
        myThread11.setPriority(10);
        //获取优先级
        System.out.println(myThread1.getPriority()+"  "+myThread1.getName());
        System.out.println(myThread11.getPriority()+"  "+myThread11.getName());
        myThread1.start();
        myThread11.start();
    }
}

4,2 线程控制-----sleep

概述:使当前正在执行的线程休眠,以指定毫秒数暂停

/*线程控制-线程睡眠演示案例
* sleep()在哪个线程中调用,就阻塞哪个方法*/
public class SleepD {
    public static void main(String[] args) {
        MySleep mySleep1 = new MySleep("彭于晏");
        MySleep mySleep2 = new MySleep("金城武");
        mySleep1.start();
        mySleep2.start();
    }
}
class  MySleep extends Thread {
    private String name;
    public MySleep(String name) {
        super(name);
    }

    @Override
    public void run() {
      for(int i=0;i<20;i++){
          System.out.println(getName()+" "+i+""+new Date());
          try {
              Thread.sleep(1000);//休眠1秒
          } catch (InterruptedException e) {
              e.printStackTrace();
          }
      }
    }
}

4,3 join线程控制----加入线程

Public final void join(long miles)该方法是让调用该方法的线程执行完毕之后,再去执行其他线程,不设置则执行完毕之后,再执行其他线程。

/*线程控制-线程睡眠演示案例
* sleep()在哪个线程中调用,就阻塞哪个方法*/
public class SleepD {
    public static void main(String[] args) {
        MySleep mySleep1 = new MySleep("彭于晏");
        MySleep mySleep2 = new MySleep("金城武");
        MySleep mySleep3= new MySleep("林青霞");
        mySleep1.start();
        mySleep1.setPriority(1);
        try {
            mySleep1.join();//彭于晏先运行完再运行其他线程
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        mySleep2.start();
        mySleep3.start();
    }
}
class  MySleep extends Thread {
    private String name;
    public MySleep(String name) {
        super(name);
    }

    @Override
    public void run() {
      for(int i=0;i<20;i++){
          System.out.println(getName()+" "+i+""+new Date());
         /* try {
              Thread.sleep(1000);//休眠1秒
          } catch (InterruptedException e) {
              e.printStackTrace();
          }*/
      }
    }
}

4,4线程控制—线程礼让yield()

Public static void yield()线程礼让可以让线程间的抢占趋于和平,你运行一下我运行一下,但是仅仅是让抢占不激烈,并不是说一定每个线程的执行时间或执行次数相同。

/*线程控制-线程睡眠演示案例
* sleep()在哪个线程中调用,就阻塞哪个方法*/
public class SleepD {
    public static void main(String[] args) {
        MySleep mySleep1 = new MySleep("彭于晏");
        MySleep mySleep2 = new MySleep("金城武");
        MySleep mySleep3= new MySleep("林青霞");
        mySleep1.start();
        mySleep1.setPriority(5);
       /* try {
            mySleep1.join();//彭于晏先运行完再运行其他线程
        } catch (InterruptedException e) {
            e.printStackTrace();
        }*/
        mySleep2.start();
        mySleep3.start();
    }
}
class  MySleep extends Thread {
    private String name;
    public MySleep(String name) {
        super(name);
    }

    @Override
    public void run() {
      for(int i=0;i<20;i++){
          System.out.println(getName()+" "+i+""+new Date());
         /* try {
              Thread.sleep(1000);//休眠1秒
          } catch (InterruptedException e) {
              e.printStackTrace();
          }*/
          Thread.yield();//线程礼让
      }
    }
}

4,5线程守护

public final void SetDaemon(boolean on)

注意事项:

1,当线程只有守护线程,jvm会退出

2,在线程开始前设置守护线程

/*public final void SetDaemon(boolean on)
刘备跑完,张飞和关羽的线程也会结束*/
public class DaemonD extends Thread{
    private String name;

    public DaemonD(String name) {
        super(name);
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(getName()+"  "+i);
        }
    }
}
class DaemonDemo{
    public static void main(String[] args) {
        DaemonD daemonD1 = new DaemonD("关羽");
        DaemonD daemonD2 = new DaemonD("张飞 ");
        //在线程启动前添加后台线程
        daemonD1.setDaemon(true);
        daemonD2.setDaemon(true);
        daemonD1.start();
        daemonD2.start();
        Thread.currentThread().setName("刘备");
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName()+":"+i);
        }
    }
}

4,6线程控制—终止线程

public final void stop()

public void interrupt()

interrupt方法与stop不同,它走的是异常处理机制,如果在线程终止前还有一些代码必须执行的话,你可以把这些代码写在finally中或try-catch结构外。

注意:

public void interrupt()
//中断线程。
public static boolean interrupted()
//测试当前线程是否已经中断。
/*线程中断,stop方法本质上是不安全的,它会立马终止调用该方法的线程,让主线程后面的代码还没有执行就结束了
* interrupt只是中断调用该方法的线程,主线程后面的代码依然会执行*/
public class InterruptD extends Thread {
    private String name;

    public InterruptD(String name) {
       super(name);
    }

    @Override
    public void run() {
        System.out.println("线程"+getName()+"开始了"+new Date());
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            System.out.println("线程被中断了");
        }
        System.out.println("线程"+getName()+"结束了"+new Date());
    }
}
class MyInterrupt{
    public static void main(String[] args) {
        //创建线程对象
        InterruptD interruptD1 = new InterruptD("李莫愁");
        InterruptD interruptD2 = new InterruptD("洪凌波");
        interruptD1.start();
        try {
            //只给线程三秒钟时间,不然就干掉该线程,执行主线程剩下的代码
            Thread.sleep(3000);//让线程休眠三秒
            interruptD1.interrupt();//让线程中断
            System.out.println("sdfjslfjks");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

4,7实现多线程的另一种方式

/*1,实现Runnable接口
* 2,重写run方法
* 3,创建自定义线程类对象
* 4,创建Thread对象并将自定义线程对象作为参数进行传递
* 5,start()*/
public class ThreadD1 implements Runnable {

    @Override
    public void run() {
        for (int i=0;i<500;i++){
            System.out.println(":"+i);
        }
    }

}class ThreadD1Demo{
    public static void main(String[] args) {
     ThreadD1 threadD1=new ThreadD1();
     Thread thread=new Thread(threadD1);
    }
}

案例:

/*多线程模拟电影院售票*/
public class SellTicket extends Thread{
    public static int tickets=100;
    /*为什么要设置成static,因为被静态修饰的成员变量可以被所有对象共享,并且只在类加载的时候进行一次初始化
    * 而非是对象所有,在创建对象时被初始化*/
    @Override
    public void run() {
     while(true){
         if(tickets>-1){
             System.out.println(getName()+"正在售票,剩余"+(tickets--)+"张票");
         }
     }
    }
}
class TicketWindow{
    public static void main(String[] args) {
        SellTicket window1=new SellTicket();
        SellTicket window2=new SellTicket();
        SellTicket window3=new SellTicket();
        window1.setName("窗口1");
        window2.setName("窗口2");
        window3.setName("窗口3");
        window1.start();
        window2.start();
        window3.start();

    }
}
/*自定义三个线程模拟电影院三个窗口售票*/
public class SellTicket2 implements Runnable{
     private  static int tickets=100;
    @Override
    public void run() {
        while(true){
            if(tickets>-1){
        System.out.println(Thread.currentThread().getName()+"正在售票,剩余"+(tickets--));
            }
        }
    }
}
class TicketWindows{
    public static void main(String[] args) {
        //创建自定义类对象
        SellTicket2 sellTicket2=new SellTicket2();
        //将自定义类对象作为参数传入
        Thread ticketWindow1=new Thread(sellTicket2,"窗口1");
        Thread ticketWindow2=new Thread(sellTicket2,"窗口2");
        Thread ticketWindow3=new Thread(sellTicket2,"窗口3");
        ticketWindow1.start();
        ticketWindow2.start();
        ticketWindow3.start();
    }
}

5,1解决问题–同步代码块

判断可能出现多线程安全问题的依据:

1,是否是多线程

2,是否有共享数据

3,是否有多条语句操作共享数据

思路:

考虑把这多条操作共享数据的语句进行包裹,当某一个程序在执行被包裹的语句时,其他线程不能执行这些语句。

怎么包裹?

java为我们提供了一种机制可以解决我们的需求:同步机制

格式:

synchronized(对象){

多条操作共享数据的语句;}

对象:任意对象,这个对象起到了一个锁的作用。要将对象提前创建,作为一个参数传到synchronized括号中。

同步代码块前提:

1,多线程

2,多个线程使用的是同一个锁对象

同步代码块的优缺点:

同步代码块的好处是解决了多线程的安全问题,但由于每一个线程在执行之前都要去判断一下锁对象,这样是很浪费资源的。会降低程序运行的效率。

将synchronized写在非静态方法声明上面,锁对象是谁?

this

将将synchronized写在静态方法声明上面,锁对象是谁?

是成员变量所在的class文件,类名.class,字节码文件对象(反射会讲)。

/*利用同步代码块来模拟电影院中三个窗口售票的情况*/
public class SynchronizedD implements Runnable {
    private  int tickets=100;
    Object obj=new Object();
    @Override
    public void run() {
        synchronized (obj) {
        while(true){

            if(tickets>-1){
                try {
                    Thread.sleep(200);//模拟网络延迟
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "正在售票,剩余票数" + (tickets--)+"张");
            }
        }
     }
    }
}
class TicketWindows1{
    public static void main(String[] args) {
        //创建自定义类对象
        SynchronizedD ticketWindows=new SynchronizedD();
        Thread ticketWindow1 = new Thread(ticketWindows,"窗口1");
        Thread ticketWindow2 = new Thread(ticketWindows,"窗口2");
        Thread ticketWindow3 = new Thread(ticketWindows,"窗口3");
        ticketWindow1.start();
        ticketWindow2.start();
        ticketWindow3.start();
    }
}

5,2 lock锁对象

概述:这是一个接口提供了比synchronized更广泛的功能

Lock的实现子类:

ReentranLock:

构造方法:

public ReentrantLock()

成员方法:

public void lock()

获取锁。

public void unlock()

试图释放此锁。

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class LockD implements Runnable {
    private  int tickets=100;
    Lock lock=new ReentrantLock();
    @Override
    public void run() {

            while(true){
                lock.lock();//上锁
                if(tickets>-1){
                    try {
                        Thread.sleep(200);//模拟网络延迟
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "正在售票,剩余票数" + (tickets--)+"张");
                }
                lock.unlock();//下锁
            }

    }

    }
class TicketWindows2{
    public static void main(String[] args) {
        //创建自定义类对象
        LockD ticketWindows=new LockD();
        Thread ticketWindow1 = new Thread(ticketWindows,"窗口1");
        Thread ticketWindow2 = new Thread(ticketWindows,"窗口2");
        Thread ticketWindow3 = new Thread(ticketWindows,"窗口3");
        ticketWindow1.start();
        ticketWindow2.start();
        ticketWindow3.start();
    }
}

5.3死锁

什么是死锁?

死锁就是指两个或两个以上的线程在执行过程中,因为争夺资源而产生的一种相互等待的现象。

/*死锁案例的演示*/
public class DeadLockD extends Thread{
    private  static  Object lockA=new Object();
   private static Object lockB=new Object();
    private  boolean flag;
      public DeadLockD (boolean flag){
          this.flag=flag;
      }
    @Override
    public void run() {
        if (flag) {
            synchronized (lockA){
                System.out.println("if lockA");
                synchronized (lockB){
                    System.out.println("if lockB ");
                }
            }
        }else {
             synchronized(lockB){
                 System.out.println("else lockB");
                 synchronized(lockA){
                     System.out.println("else lockA");
                 }
             }
        }
    }
}
class DeadLock{
    public static void main(String[] args) {
        DeadLockD d1=new DeadLockD(true);
        DeadLockD d2=new DeadLockD(false);
         d1.start();
         d2.start();
    }
}

问题:

1,重复数据

线程执行的随机性,cpu执行效率高

2,数据不匹配

cpu执行的原子性和线程的随机性

根本原因:

1,是否是多线程

2,是否有共享资源

3,是否有多条语句操作共享数据

解决方案:

加锁

6,线程组Thread-Group

package com.company.Thread;
/*线程组演示案例
* 默认情况下,所有线程都属于main线程组
* 设置线程组的好处:方便统一管理线程*/
public class ThreadGroupD implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println(Thread.currentThread().getName()+":"+i);
        }
    }
}
class  MyThreadGroup{
    public static void main(String[] args) {
        method1();
        method2();
    }

    private static void method2() {
        //构建一个新的线程组
        ThreadGroup threadGroup = new ThreadGroup("新线程组");
        ThreadGroupD t1 = new ThreadGroupD();
        Thread thread1 = new Thread(threadGroup,t1, "李莫愁");
        Thread thread2 = new Thread(threadGroup,t1, "公孙绿萼");
        //输出两个线程组的名称
         System.out.println(thread1.getThreadGroup().getName());
         System.out.println(thread2.getThreadGroup().getName());
    }

    private static void method1() {
        ThreadGroupD t1 = new ThreadGroupD();
        Thread thread1 = new Thread(t1, "李莫愁");
        Thread thread2 = new Thread(t1, "公孙绿萼");
        //分别返回两个线程所在的线程组
        ThreadGroup threadGroup1=thread1.getThreadGroup();
        ThreadGroup threadGroup2=thread2.getThreadGroup();
       System.out.println( threadGroup1.getName() );
       System.out.println( threadGroup2.getName() );
       //通过链式编程获取main方法的线程组名称
        System.out.println(Thread.currentThread().getThreadGroup().getName());
    }
}

7,线程池

**概述:**程序启动一个新线程成本是比较高的,因为要一直与操作系统进行交互。而使用线程池可以很好的提高性能,尤其是当程序中要大量创建生命周期较短的线程时,就更应该使用线程池。

**好处:**线程池里面的每一个代码结束后,并不会死亡,而是再次回到线程池中成为空闲状态,等待下一个对象继续使用。

package com.company.Thread;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/*线程池对象演示*/
public class ThreadPoolD implements Runnable{

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println(Thread.currentThread().getName()+":"+i);
        }
    }
}
class MyTP{
    public static void main(String[] args) {
        //创建一个线程池
        ExecutorService threadPool = Executors.newFixedThreadPool(2);//放两个线程的线程池
       //创建两个线程
        threadPool.submit(new ThreadPoolD());
        threadPool.submit(new ThreadPoolD());
        //停止先前的线程并不会接受新的任务
        threadPool.shutdown();
    }
}

8,Callable泛型接口

/*线程实现的第三种方式
* Callable
* 好处:
* 1,可以有返回值
* 2,可以抛出
* 弊端:代码比较复杂,所以一般不用*/
public class CallableD implements Callable {
    @Override
    public Object call() throws Exception {
        for (int i = 0; i < 20; i++) {
            System.out.println(Thread.currentThread().getName()+"  "+i);
        }
        return null;
    }
}
class MyCallable{
    public static void main(String[] args) {
        //创建两个线程的线程池
        ExecutorService threadPool = Executors.newFixedThreadPool(2);
        threadPool.submit(new CallableD());
        threadPool.submit(new CallableD());
        //关闭线程池
        threadPool.shutdown();
    }
}
/*带泛型的Callable接口*/
class CallableD2 implements Callable<Integer>{
     private int num;
     public  CallableD2(int num){
         this.num=num;
     }
    @Override
    public Integer call() throws Exception {
         int result=0;
        for (int i = 0; i <= num; i++) {
            result +=i;
        }
        return result;
    }
}
class MyCallable2 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //创建两个线程的线程池
        ExecutorService threadPool = Executors.newFixedThreadPool(2);
        Future<Integer> result1 = threadPool.submit(new CallableD2(5));
        Future<Integer> result2 = threadPool.submit(new CallableD2(100));
        System.out.println(result1.get());
        System.out.println(result2.get());
        //关闭线程池
        threadPool.shutdown();
    }
}

9,定时器

概述:可以指定程序在某个规定的时间做规定的工作(可以是重复的工作),是一个线程工具,可用来调度多个定时任务,以后台的方式执行。

TImerTask:可以由定时器指定一次或重复执行的任务

注意:cancel方法要在run方法中调用

import java.util.Timer;
import java.util.TimerTask;

public class TimerTaskD extends TimerTask {
    Timer time;
//创建一个Timer成员变量作为参数,才可以正确使用cancel方法
    public TimerTaskD(Timer time) {
        this.time = time;
    }

    public TimerTaskD() {
    }

    @Override
    public void run() {
        System.out.println("有内鬼,终止交易!");
        time.cancel();
    }
}
class TaskDemo{
    public static void main(String[] args) {
        //创建定时器对象
        Timer timer=new Timer();
        //执行Task任务
        timer.schedule(new TimerTaskD(timer),3000,1000);
    }
}
import java.io.File;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

/*定时删除文件及文件夹*/
public class DeleteFolder extends TimerTask {
     private Timer timer;

    public DeleteFolder(Timer timer) {
        this.timer = timer;
    }

    @Override
    public void run() {
        File file =new File("/Users/zhoukun/Desktop/java/testDoc");
        deleteFolder(file);
        timer.cancel();
    }

    private void deleteFolder(File srcFolder) {
        //获取指定文件夹下所有的File对象
        File [] files =srcFolder.listFiles();
        if(files!=null){
            for(File file:files){
                if(file.isDirectory()){//文件夹
                    deleteFolder(file);
                }else{//文件
                    System.out.println(srcFolder.getName()+"------"+file.delete());
                }
            }
        }
    }

}
 class DeleteFolderDemo{
     public static void main(String[] args) {
         //创建Timer对象
         Timer timer = new Timer();
         //设置执行时间
         String time = "2020-12-13 09:59:00";
         SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
         Date date = null;
         try {
             date = simpleDateFormat.parse(time);
         } catch (ParseException e) {
             e.printStackTrace();
         }
         timer.schedule(new DeleteFolder(timer),date);
     }
 }

10,匿名内部类实现多线程

package com.company.Thread;
/*匿名内部类实现线程*/
public class Anonymity {
    public static void main(String[] args) {
        //方式1:继承Thread类
        new Thread() {
            @Override
            public void run() {
                for (int i = 0; i < 20; i++) {
                    System.out.println(Thread.currentThread().getName() + " " + i);
                }
            }
        }.start();
        //方式2:实现runnable接口
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 20; i++) {
                    System.out.println(Thread.currentThread().getName() + " " + i);
                }
            }
        }){

        }.start();
        //方式3:面试可能会考,会走Thread的run方法
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("hello");
            }
        }){
            @Override
            public void run() {
                System.out.println("world");
            }
        }.start();
    }
}

总结

sleep方法和wait方法的区别?

sleep 必须指定休眠时间,并且不释放锁

wait可以不用指定时间,并且可以释放锁

为什么notify,wait,notyfyAll等方法都定义在object类里面?

因为这些方法的调用都是依赖于锁对象存在的,而同步代码块的锁对象是任意锁。

而object代码的任意对象都是锁对象,所以就将这些方法定义在object类里面。

线程的生命周期:

理想情况:创建-------就绪------执行------死亡

一般情况:创建-------就绪------阻塞------就绪-------执行------死亡

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java多线程意义在于提高程序的并发性和响应性。通过使用多线程,可以同时执行多个任务,从而提高程序的运行效率和性能。 具体来说,Java多线程意义包括以下几个方面: 1. 提高程序的并发性:多线程可以使程序同时执行多个任务,充分利用计算机的多核处理器和资源,提高程序的并发性。通过将任务分解为多个线程并行执行,可以加快程序的运行速度。 2. 提高程序的响应性:在单线程程序中,如果某个任务需要花费较长时间才能完成,那么整个程序都会被阻塞,无法响应其他任务。而使用多线程可以将耗时的任务放在一个线程中执行,其他线程可以继续执行其他任务,从而提高程序的响应性。 3. 改善用户体验:在图形界面应用程序中,使用多线程可以使界面保持响应,不会因为某个任务的阻塞而导致界面卡顿或无响应。例如,在下载文件时,可以将下载任务放在一个线程中执行,同时界面仍然可以响应用户的操作。 4. 实现复杂的并发控制:多线程可以实现复杂的并发控制逻辑,例如生产者-消费者模型、读写锁、线程池等。通过合理地使用多线程,可以实现高效的资源共享和协作。 5. 提高系统的可扩展性:使用多线程可以将任务分解为多个独立的子任务,每个子任务由一个线程负责执行。这样,当需要增加处理能力时,只需增加线程的数量,而不需要修改整个程序的结构。 总之,Java多线程意义在于提高程序的并发性和响应性,改善用户体验,实现复杂的并发控制,以及提高系统的可扩展性。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值