java基础:多线程。

前言

进程与线程
  进程:可以理解为可以独立运行的应用程序,
  线程:进程中的控制单元,一个进程至少存在一个主线程,一个进程可以有多个线程,可以让一个程序同时执行多个任务。
并发与并行
  并发:可以理解为一个CPU上同时执行多个任务,在逻辑上是同时发生,但并不是物理上的同时执行,因为一个CPU在某一时刻只能执行一个指令,通过快速切换的方式运行不同的指令达到,即指令的执行并不是在同一时刻发生的(当有多个线程进行操作时,如果只有一个CPU,不可能同时进行多个线程的操作,只能根据CPU的调度不同的时间段分配给不同的线程执行,即同一时刻不能执行多个指令)。
  并行:可以理解为多个CPU同时执行多个任务,即多个指令可以在多个CPU上同一时刻执行(有多个CPU时,是可以同时执行不同的线程的,当一个CPU在执行一个指令时,另一个CPU可以执行另一个指令,两个线程可以互不抢占CPU的资源,即同一时刻可以执行指令多个)。

一、线程的创建

  线程的创建常用的两种方式:继承Thread类、实现Runnable接口或者Callable接口。

  1. 继承Thread类创建线程
      特点:实现简单、不能继承其他类、不能共享同一资源(如成员变量)。
    代码案例:
public class Thread01 {
    public static void main(String[] args) {
        MyThread myThread1 = new MyThread("MyThread-1");
        myThread1.start();

        MyThread myThread2 = new MyThread("MyThread-2");
        myThread2.start();
    }
}
//继承Thread
class MyThread extends Thread{
    
    MyThread(String name){
        super(name);
    }
    
    @Override
    public void run() {
        while (true){
            System.out.println(this.getName()+"run ------->");
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
  1. Runnable 接口来创建线程
    特点:可以继承其他类、可以多个线程处理同一资源,一般采用该方式实现多线程
    代码案例:
public class T_Runnable {
    public static void main(String[] args) {
        MyRunnable myRunnable = new MyRunnable();
        Thread t1 = new Thread(myRunnable,"线程一");
        t1.start();
        Thread t2 = new Thread(myRunnable,"线程二");
        t2.start();
    }
}
//实现Runnable
class MyRunnable implements Runnable{
    @Override
    public void run() {
        while (true){
            System.out.println(Thread.currentThread().getName()+":execute..............");
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

使用Lambda表达式:

public class T_Lambda {
    public static void main(String[] args) {
        //jdk8,只有一行时可以省略{}
        Thread t1 = new Thread(() -> {
            while (true){
                System.out.println(Thread.currentThread().getName()+"run 执行了。。。");
            }
        });
        t1.start();
    }
}

二、生命周期及状态转换。

  生命周期可以分为五个阶段:新建状态(New)、就绪状态((Runnable)、运行状态(Running)、阻塞状态(Blocked)和死亡状态(Terminated),线程的不同状态表明了线程当前正在进行的活动。
①新建状态:
  使用 new 关键字创建对象时处于新建状态,直到调用start()。
②就绪状态:
  调用start()后,进入就绪状态,进入就绪队列,等待jvm调度。
③运行状态:
  获得cpu资源,执行run()处于运行状态,此时状态可变成阻塞、就绪、死亡状态。
④阻塞状态:
  执行sleep(睡眠)、suspend(挂起)等方法,失去占用资源后,该线程从运行状态进入阻塞状态。睡眠时间到达可重新进入就绪状态。等待阻塞:执行 wait() 方法,同步阻塞:获取 synchronized 同步锁失败,其他阻塞:发出了 I/O 请求、sleep() 、join() 等。
⑤死亡状态::
  run()完成或者发生异常。
在这里插入图片描述

三、线程优先级

  优先级越高的线程获得CPU执行的机会越大,越低则反之越小,线程的优先级用1~10表示,越大优先级越高,但java代码中不能通过调优先级去调度线程的先后执行的顺序,因为这是CPU进行调度的。
Thread中优先级的静态变量:
①static int MAX_PRIORITY (最高优先级,值为10)
②static int MIN_PRIORITY (最低优先级,值为1)
③static int NORM_PRIORITY (普通优先级,值为5)
  使用案例:

public class Ex1 {
    public static void main(String[] args) {
        //优先级
            Thread min = new Thread(new MinPriority(),"优先级低的线程");
            Thread max = new Thread(new MaxPriority(),"优先级高的线程");
            max.setPriority(Thread.MAX_PRIORITY);
            min.setPriority(Thread.MIN_PRIORITY);
            min.start();
            max.start();
    }
}
class MaxPriority implements Runnable{
    @Override
    public void run() {
        for (int x = 0 ; x < 10; x++){
            System.out.println(Thread.currentThread().getName()+"正在输出"+x);
        }
    }
}
class MinPriority implements Runnable{
    @Override
    public void run() {
        for (int x = 0 ; x < 10; x++){
            System.out.println(Thread.currentThread().getName()+"正在输出"+x);
        }
    }
}

四、线程休眠。

  使用静态方法sleep(long millis)可以让线程暂停一段时间,进入休眠状态。
  使用案例:

public class Ex2_Sleep {
    public static void main(String[] args) {
       new Thread(new TSleep()).start();
        for (int i = 0; i < 10; i++){
            System.out.println("main ....." + i );
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }
}
class TSleep implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 10; i++){
            System.out.println("TSleep ....." + i );
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

五、线程让步

  线程让步,是指某个线程在执行到某种情况下,把CPU资源让给其他线程执行。通过调用yield()方法实现。
  使用案例:

public class Ex3_yield {
    public static void main(String[] args) {
        YieldThread y1 = new YieldThread("线程一");
        YieldThread y2 = new YieldThread("线程二");
        y1.start();
        y2.start();
    }
}

class YieldThread extends Thread{

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

    @Override
    public void run() {
        for (int i = 0 ;i < 10; i++){
            System.out.println(Thread.currentThread().getName()+"----"+i);
            if (i==3){
                System.out.println(Thread.currentThread().getName()+"让步");
                Thread.yield();
            }
        }
    }
}

六、线程插队

  当某个线程调用其他线程的join()方法时,被调用的线程将阻塞,直到调用join()方法的线程执行完之后,被调用的线程才会继续执行。
  使用案例:

public class Ex4_Join {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(new ThreadJoin(),"线程一");
        t1.start();
        for(int i = 0 ;i< 10 ; i++){
            System.out.println(Thread.currentThread().getName() + "输入" + i);
            if (i == 2){
                t1.join();
            }
            Thread.sleep(500);
        }
    }
}
class ThreadJoin implements Runnable{
    @Override
    public void run() {
        for(int i = 0 ;i< 10 ; i++){
            System.out.println(Thread.currentThread().getName() + "输入" + i);
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

线程安全:

  在多个线程同时调用共享资源时,可能会产生线程安全问题。

  1. 同步代码块处理线程安全问题。
      使用synchronized 修饰同步代码块。
//加入同步代码块
public class Ex6_Security {
    public static void main(String[] args) {
        SeThread1 s1 = new SeThread1();
        new Thread(s1,"线程一").start();
        new Thread(s1,"线程二").start();
        new Thread(s1,"线程三").start();
        new Thread(s1,"线程四").start();
    }
}
class SeThread1 implements Runnable{
    private int ticket = 1000;

    private Object lock = new Object();

    @Override
    public void run() {
        while (true){
            synchronized (lock){
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (ticket > 0){
                    System.out.println(Thread.currentThread().getName() + "卖出第:"+ ticket-- +"张票");
                }else {
                    break;
                }
            }
        }

    }
}
  1. 同步方法块处理线程安全问题。
      使用synchronized 修饰同步方法。
//加入同步方法
public class Ex7_Security {
    public static void main(String[] args) {
        SeThread2 s1 = new SeThread2();
        new Thread(s1,"线程一").start();
        new Thread(s1,"线程二").start();
        new Thread(s1,"线程三").start();
        new Thread(s1,"线程四").start();
    }
}
class SeThread2 implements Runnable{
    private static int ticket = 1000;

    private Object lock = new Object();

    @Override
    public void run() {
        while (true){
            checkTicket();
            if (ticket <= 0){
                break;
            }
        }
    }
    //同步方法,同步方法的锁对象就是当前类的一个对象,这个对象使用的就是this
    //如果是静态同步方法,锁对象为:当前类名.class ---> 当前类所对应的字节码文件对象。
    //加入锁代码效率会降低
    public static synchronized void checkTicket(){
        if (ticket > 0){
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "卖出第:"+ ticket-- +"张票");
        }
    }
}
  1. 死锁问题
      死锁问题一般出现在嵌套锁的场景(所以应该尽量避免使用嵌套锁),当两个线程同时等待对方释放锁的时(双方都拿着对方需要的锁互不让步,最后谁也解不开(●’◡’●)…),会使程序停滞,这就是是死锁现象。
//死锁
public class Ex8_Security {
    public static void main(String[] args) {
        SeThread3 s1 = new SeThread3(true);
        SeThread3 s2 = new SeThread3(false);
        new Thread(s1,"线程一").start();
        new Thread(s2,"线程二").start();
    }
}
class SeThread3 implements Runnable{

    static Object lock1 = new Object();
    static Object lock2 = new Object();

    private boolean flag;

    SeThread3(boolean flag){
        this.flag = flag;
    }

    @Override
    public void run() {
        if (flag){
            while (true){
                synchronized (lock1){
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+"if --- lock1--->");
                    synchronized (lock2){
                        System.out.println(Thread.currentThread().getName()+"if ---lock2--->");
                    }
                }
            }
        }else {
            while (true){
                synchronized (lock2){
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+"else---lock2--->");
                    synchronized (lock1){
                        System.out.println(Thread.currentThread().getName()+"else----lock1--->");
                    }
                }
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值