Java笔记梳理(六)查漏补缺-[Java多线程]

        今天记录一下线程吧。

========== 【什么是线程】==========

        Java中在遇到并发时,常常会用多线程来解决,首先我们先来了解一下什么是线程,面试中最常被问到的就是进程和线程的区别是什么。
        线程(英语:thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。
        线程和进程的区别
        1. 进程是操作系统资源分配的基本单位,而线程是任务调度和执行的基本单位。
        2.操作系统会为进程分配资源,而不会为线程分配资源,线程想要使用资源只能从其所属进程获取,一个进程中的各个线程共享这个进程的所有资源。
        3.线程是进程的,一个进程可以有多个线程,一个线程只能属于一个进程,线程不能脱离进程单独存在。
        4.一个进程至少要有一条进程。
        就这四条吧,这只是最基本的,往深了挖应该还有好多,不过以我目前的水平,我觉得还是算了,不过先码住。

========== 【线程的基本状态】==========

        新建:线程刚被创建出来的状态。
        可执行:线程被创建出来后,调用start()方,线程等待被调度算法选中,处于可执行状态。
        执行:线程被调度算法选中,获取cpu,处于执行状态。
        阻塞:由于某事件的发生,导致线程无法继续执行,暂时停止运行,处于阻塞状态。
        死亡:线程执行结束,或者因某事件发生而抛出异常,线程就处于死亡状态,死亡线程不可再生。

========== 【线程的三种实现方式】==========

继承Thead类

        定义一个类继承Thread类,这个类就变成了线程类,然后重写Thread类中的run方法,当调用该线程类的start方法时就会执行run方法中的代码。

public class Test1 {
public static void main(String[] args) {
    T1 t1 = new T1();
    T1 t2 = new T1();
    t1.start();
    t2.start();
    System.out.println("main");
}
static class T1 extends Thread {
    @Override
    public void run() {
        //获得线程名
        String n = getName();
        //1到1000
        for (int i = 1; i <= 1000; i++) {
           System.out.println(n+" - "+i);          
        }
    }
}
}
实现Runnable接口

        准备一个类实现Runnable接口,该类就变成了一个线程类,然后,实现Runnable接口中的run方法,当调用该线程类中的start()方法时,会执行run方法中的代码。

public class Test2 {
public static void main(String[] args) {
    R1 r1 = new R1();
    Thread t1 = new Thread(r1);
    Thread t2 = new Thread(r1);
    //线程启动后,自动执行 r1.run()
    t1.start();
    t2.start();
}
static class R1 implements Runnable {
    @Override
    public void run() {
        //获得正在执行这行代码的线程(当前线程)
        Thread t = Thread.currentThread();
        //获得线程名
        String n = t.getName();
        //1到1000
        for (int i = 1; i <= 1000; i++) {
           System.out.println(n+" - "+i);          
        }
    }
}
}
实现Callable接口FutureTask包装器来创建线程

        实现Callable接口需要实现它的call()方法,这种方式可以创建一个带有返回值的线程,实现Callable接口的目的,主要是FutureTask这个类引用了Callable接口,所以它的构造函数需要传入一个Callable接口的实现类。FutureTask间接实现了Runnable,接口和Future接口。Runnable接口中提供了创建线程的方法,Future接口中提供了设置任务超时时间的,判断任务状态等一系列方法。两者结合使用可以创建一个带有返回值的线程。

public class Animal implements Callable<String>{
	@Override
	public String call() throws Exception {
		return null;
	}
}
class test{
	public static void main(String[] args) {
		//创建Callable接口的实现类对象
		Callable<String> AnimalCallable = new Animal();   
		//通过FutureTask来构建任务未来任务
		FutureTask<String> oneTask = new FutureTask<String>(AnimalCallable);   
		//将任务传给Thread类构建线程对象
		Thread oneThread = new Thread(oneTask);   
		//启动线程
		oneThread.start(); 
	}
}

        总结:三种实现方式的区别
        1.继承Thread类的方式,由于java单继承的特点,会占用继承位置,有些浪费。实现Runnable接口和Callable接口的方式,避免了这种问题。
        2.继承Thread类和实现Runnable接口的方式,创建的线程没有返回值,而实现Callable接口创建的线程有返回值。
        3.常用的还是Runnable接口的方法。具体看业务需求。

========== 【线程的常用方法】==========

方法作用
currentThread()获取当前运行线程对象的引用
yield()线程让步,表示当前线程愿意让出cpu给其他线程
sleep()让线程休眠一段时间
start()启动线程
setName()设置线程名称
getName()获取线程名称
getName()获取线程名称
interrupt()中断当前线程
setDaemon()设置当前线程是否为守护线程,当运行的唯一线程都是守护进程线程时,Java虚拟机将退出
join()将当前线程加入主线程,当前线程执行完之后,主线程才能继续执行
setPriority()设置线程优先级:默认为5,优先级别1-10

========== 【线程安全和数据访问冲突】==========

问题:

        当时用多个线程共同访问同一个资源时,非常容易出现线程安全的问题,例如当多个线程同时对一个数据进行修改时,会导致某些线程对数据的修改丢失。而多个同时访问一个资源,其中一个线程修改了资源,就会出现数据访问冲突的问题,就会导致其他线程访问到的数据不完整。

解决方法:线程同步
1.synchronized关键字实现线程同步

        同步方法:即将目标方法用synchronized关键字修饰之后,目标方法就会变成同步方法,在Java中,每个对象都有一个内置的对象所锁,当线程访问被synchronized关键字修饰的方法,即同步方法是,首先会获得这个对象锁,然后再去执行相应代码,等到执行结束之后,再释放锁,在此期间,此方法同一时间只允许被一个线程访问。这就保证了,多线程访问同一方法时,线程需要排队执行。避免了出现线程不安全和数据访问冲突问题。但是这样会大大降低程序运行的效率。
        同步代码块:即将目标方法可能只有部分代码会引起线程安全问题,可以用synchronized关键字修饰该部分代码,该部分代码就变成同步代码块,该代码块同一时间只允许被一个线程访问。

2.使用Lock锁

        可以使用Lock锁机制来实现线程同步,Lock锁机制提供比synchronized关键字更加灵活的体验,Lock可以灵活的获取释放锁。使用Lock也可以解决线程不安全和数据访问冲突的问题。

  • 使用Lock的步骤:
  • 1.创建Lock实现类的对象
  • 2.使用Lock对象的lock方法加锁
  • 3.使用Lock对象的unlock方法解锁
  • 注意:可把unlock方法的调用放在finally代码块中,保证一定能解锁。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值