java-多线程基础入门讲解

    科技2024-04-17  88

    多线程

    线程的创建和启动

    java.lang.Thread 是java中的线程类,所有的线程对象都必须是Thread类或其子类的实例

    每个线程的作用,就是完成我们给它指定的任务,实际上就是执行一段我们指定的代码.我们只需要在Thread类的子类中重写run方法.

    java中通过继承Thread类来创建并启动一个新的线程的步骤如下

    定义Thread类的子类,并重写Thread类的run方法,run方法中的代码就是线程的执行任务创建Thread子类的对象,这个对象就代表了一个要独立运行的新线程调用线程对象的start方法来启动该线程 class MyThread extends Thread{ public void run(){ for(int i=0;i<100;i++){ System.out.println("hello world!"); } } } class Main{ public static void main(String[] args){ Thread thread = new MyThread(); thread.start(); } } // 继承Thread类来创建线程 class Main{ public static void main(String[] args){ Thread t = new Thread(){ for(int i=0;i<100;i++){ System.out.println("hello world!"); } } } } // 使用匿名内部类的方式创建线程对象 class Main{ public static void main(String[] args){ Thread t = new Thread(new MyThread()); t.start(); } } class MyThread implements Runnable{ public void run(){ /* 线程要执行的任务 */ } }

    线程的名字

    可以通过Thread类中的currentThread方法,可以获取当前线程的对象,然后调用线程对象的getName方法

    String name = Thread.currentThread().getName();

    默认情况下,主线程中,创建出来的线程,它们都会有一个默认的名字;

    public Thread(){ init(null,null,"Thread-"+nextThreadNum(),0); }

    其中,“Thread-”+nextThreadNum() 就是在拼接处这个线程默认的名字,Thread-0,…

    我们也可以创建线程对象的时候,给它设置一个指定的名字

    Thread t = new Thread("t线程"); // 或者 Thread t = new Thread(new Runnable(){ public void run(){ /* 线程任务 */ } },"t线程"); // 或者 Thread t = new Thread(); t.setName("t线程");

    线程的分类

    java中,线程可以分为以下两种

    前台线程,又叫做执行线程,用户线程后台线程,又叫做守护线程,精灵线程

    前台线程:

    这种线程专门用来执行用户编写的代码,地位高,JVM是否会停止,取决于这种线程是否执行完.

    后台线程:

    这种线程是用来给前台线程服务的,给前台线程提供一个良好的运行环境,地位低,jvm是否停止,与他无关

    设置后台线程

    class DaemonTest{ public static void main(String[] args){ Thread t = new Thread(); t.setDaemon(true); t.start(); } }

    线程优先级

    线程的优先级使用int类型数字表示,最大是10,最小是1,默认是5

    Thread t1 = new Thread(); t1.setPriority(Thread.MAX_PRIORITY);

    线程组

    java中使用java.lang.ThreadGroup 类来表示线程组,它可以对一批线程进行管理,对线程组进行操作,同时也会对线程组里面的这一批线程操作.

    创建线程组的时候,需要指定该线程组的名字

    也可以指定其父线程组,如果没有指定,那么这个新创建的线程组的父线程组就是档期线程组

    class ThreadGroupTest{ public static void main(String[] args){ Thread currentThread = Thread.currentThread(); ThreadGroup currentThreadGroup = currentThread.getThreadGroup(); System.out.println(currentThreadGroup) } }

    线程组中的线程最大优先级可以设置为10;

    class Test{ public static void main(String[] args){ ThreadGroup group = new ThreadGroup("my thread group"); Thread t = new Thread(group,"t线程"); } }

    线程状态

    java.lang.Thread.State枚举类型中(内部类),定义了线程的几种状态

    new : 新建,线程刚刚被创建,还没有调用startrunnable: 可执行,start方法调用结束,线程由new->runnable,线程存活blocked: 锁阻塞,线程a和b都要执行方法test,而且方法test被加了锁,线程A先拿到了锁去执行test方法,线程b要等待a吧锁释放,这个时候线程b就是处于blockedwaiting:无限期等待,一个线程等待另外一个线程执行一个唤醒动作Ttimed_waiting:有限期等待terminated: 终止死亡

    线程变化图

    线程通信

    sleep方法

    public static native void sleep(long millis);

    该静态方法可以让当前执行的线程暂时休眠指定的毫秒数

    class SleepTest{ public static void main(String[] args){ try{ Thread.sleep(10); }catch(InterruptedException e){ e.printStackTrace(); } } }

    join方法

    public final synchronize void join(long millis); public final void join();

    使用join方法,可以让当前线程阻塞,等待另一个指定的线程运行结束后,当前线程才可以继续运行:

    线程安全

    如果有多个线程,它们在一段时间内,并发访问堆区中的同一个变量,并且有写入的操作,那么最终可 能会出数据的结果和预期不符的情况,这种情况就是线程安全问题

    我们经常会进行这样的描述:这段代码是线程安全的,那段代码是非线程安全的。 其实就是在说,这段 代码在多线程并发访问的环境中,是否会出现上述情况,也就是结果和预期不符的情况。

    线程同步

    当使用多个线程访问同一个共享变量的时候,并且线程中对变量有写的操作,这时就容易出现线程安全 问题。

    Java中提供了线程同步的机制,来解决上述的线程安全问题。

    Java中实现线程同步的方式,是给需要同步的代码进行 synchronized 关键字加锁。

    synchronized

    synchronized 关键字修饰非静态方法,默认使用 this 当做锁对象,并且不能自己另外指定 synchronized 关键字修饰静态方法,默认使用 当前类的Class对象 当做锁对象,并且不能自己另外指 定 这俩中情况的同步效果是一样的,只是锁对象不同而已

    wait和notify

    Object类中有三个方法: wait()、notify()、notifyAl

    l 当一个对象,在线程同步的代码中,充当锁对象的时候,在 synchronized 同步的代码块中,就可以调 用这个锁对象的这三个方法了。

    三个核心点:

    任何对象中都一定有这三个方法

    只有对象作为锁对象的时候,才可以调用

    只有在同步的代码块中,才可以调用

    其他情况下,调用一个对象的这三个方法,都会报错!

    synchronized 关键字,虽然可以达到线程同步的效果,但是太“霸道”了,只要一个线程拿到了锁对 象,那么这个线程无论是在运行状态,还是时间片用完,回到就绪状态,还是sleep休眠,这个线程都是 死死的拿着这个锁对象不释放,只有这个线程把线程同步的代码执行完,才会释放锁对象让别的线程使 用。 那么有没有一个方法,可以让拿到的锁的线程,即使代码没执行完,也可以把锁立即给释放了呢? 有的,这个就是 wait 方法

    Processed: 0.010, SQL: 8