多线程基础

进程和线程的区别和关系

  1. 进程:是程序一次执行结果,是系统的最基本的单位,以为进程是动态的,系统运行一个程序即是一个线程的创建,运行到消亡,在java程序中,main函数会启动一个JVM进程,而main函数所在的线程就是进程中的一个线程,也叫主线程。
  2. 线程:线程是一个比进程更小的执行单位,一个进程在执行过程中可以产生多个线程,与进程不同的是同类的多个线程共享堆和方法区的资源,但是每个线程都有自己的虚拟机栈,程序计数器,本地方法栈(私有)。
  3. 不同点:进程之间是独立的,而线程之间可能会互相影响。

并发和并行的区别

  1. 并发:同一时间段,多个任务都在执行(单位时间内,不是同时执行)
  2. 并行:单位时间内,多个任务同时进行

创建线程的方式

  1. 继承Thread类,然后重写run方法,接着调用start方法
  2. 创建Runnable实例(是执行单元,重写run方法),接着创建Thread实例,将Runnable实例传入Thread中,接着调用start方法。(这是创建线程和执行单元分开的)

线程生命周期

  1. new:初始状态,创建线程,但是还没有调用start()方法
  2. runnable:运行状态
    1. ready:调用了start方法
    2. running:线程抢到时间片,去运行
  3. blocked:阻塞状态
    1. 等待阻塞:调用Object.wait()方法时,表示线程需要进入等待状态,需要等待其他线程做出一些动作(通知或者中断)
    2. 同步阻塞:执行同步方法时,线程阻塞与锁
    3. 其他阻塞:sleep()方法和join方法
  4. terminated:终止状态,表示当前线程已近执行完毕(或者是非正常死亡)

线程中常用的API

  1. join(): API解释:wait for this thread to die ,比如:在main方法中创建一个线程叫t1,启动该线程,调用join方法 t1.join() ,此时主线程main或等待t1线程结束在执行main线程。
  2. setDaemon(true):设置为守护线程,守护线程会在非守护线程结束后自动结束。
  3. inerrput():根据interrput的API文档,当线程在wait或者join或者sleep的时候(这三种线程都是阻塞状态),可以打断(阻塞的)线程。

sleep和wait的区别

  1. 各自所在的类
    sleep是Thread中的方法,而wait是Object中的方法。
  2. 线程在阻塞时会不会释放锁
    线程调用sleep阻塞时,不会释放锁,而线程调用wait时候,会释放锁。
  3. 线程是否依赖同步
    sleep阻塞不需要依赖,而wait阻塞需要同步锁。
  4. 阻塞后是否需要被唤醒
    sleep阻塞结束后会自动变成runnable状态,wait没有设置时间的话,会一直阻塞,直到有notify或者notifyAll通知,才会变成runnable状态。

停止一个线程

  1. 使用开关方式,设置标记位
public class ShutThread extends Thread{
    private  boolean flag=true;
    @Override
    public void run() {
        while (flag){
            try {
                System.out.println("thread is running");
                Thread.sleep(1000);
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
    }
    public void shutDown(){
        flag=false;
        System.out.println("thread is destory");
    }
    public static void main(String[] args) throws InterruptedException {
        ShutThread t = new ShutThread();
        t.start();
        t.sleep(5000);
        t.shutDown();
    }
}

  1. 使用interrput()方法,打断后break或者return
package BVideoThread.part5;

public class ShutThread1 {
    public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(() -> {
            while (true) {
                try {
                    Thread.sleep(1000);
                    System.out.println("Thread is running...");
                } catch (InterruptedException e) {
                    System.out.println(" Thread is destory");
                    e.printStackTrace();
                    break; 
                }
            }
        });
        thread1.start();
        System.out.println(thread1.isInterrupted());
        Thread.sleep(5_000);
        thread1.interrupt();
        System.out.println(thread1.isInterrupted());
    }
}

synchronized关键字

synchronized是为了解决在多线程中对共享资源的访问的安全性,也保证线程的安全性
使用方式

  1. 同步实例方法:作用于当前类实例对象上的锁,当线程要访问该变量时,需要获取当前对象的锁,才能访问
  2. 同步静态方法:静态方法是属于类的,所以是作用于当前类上的锁
  3. 同步代码块:可以作用于当前类实例对象的锁,也可以作用于当前类上的锁
    问题1:有两个线程访问一个类中两个不同的同步实例方法,会不会导致互斥?

public class synchrizedTest2 {

    public static void main(String[] args) {
        thisClass st = new thisClass();
        new Thread() {
            @Override
            public void run() {
                st.m1();

            }
        }.start();
         new Thread() {
            @Override
            public void run() {
                st.T1();

            }
        }.start();

    }
}
class thisClass{
    private final Object LOCK = new Object();
    public    void m1(){
        synchronized(LOCK) {
            System.out.println("m1");
            try {
                Thread.sleep(10000);
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
    }

    public  void T1(){
        synchronized(LOCK) {
            System.out.println("T1");
            try {
                Thread.sleep(10000);
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
    }
}

问题2:如果有两个线程一个线程访问类中的静态同步方法,一个线程访问实例同步方法,会不会导致互斥?

public class synchrizedTest2 {

    public static void main(String[] args) {
        thisClass st = new thisClass();
        new Thread() {
            @Override
            public void run() {
                st.m1();

            }
        }.start();
         new Thread() {
            @Override
            public void run() {
                st.T1();

            }
        }.start();

    }
}
class thisClass{
    private final Object LOCK = new Object();
    public    void m1(){
        synchronized(thisClass.class) {
            System.out.println("m1");
            try {
                Thread.sleep(10000);
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
    }

    public  void T1(){
        synchronized(LOCK) {
            System.out.println("T1");
            try {
                Thread.sleep(10000);
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
    }
}

synchronized底层实现原理
在idea中使用javap -c类名.class 可以获取反编译代码
synchronized在代码块中使用的指令是monitorenter和monitorexit,而线程要抢的锁就是monitor(monitor对象存在于每个Java对象头中,而synchronized锁便是通过这种方式获取锁的,也就是为什么java可以任意对象获取锁)的持有权,当计时器为0时说明可以成功获取锁,获取后计数器设为1,在执行monitorexit后释放锁,计数器会设为0,表名锁释放,如果锁获取失败,那么线程就会阻塞,直达其他锁释放。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值