【Java学习笔记(十三)】之多线程与线程安全要点介绍

本文章由公号【开发小鸽】发布!欢迎关注!!!


老规矩–妹妹镇楼:

一. 线程

(一) 多线程原理

       程序启动进入main函数,JVM启动了一个进程,主线程main在main()被调用时创建,主线程运行在自己的栈空间中。之后一个新的线程启动,新的线程栈空间被创建。

       每个线程有自己的栈空间,当执行线程的任务结束时,线程自动在栈空间中释放了;当所有线程被释放时,进程就结束了。

(二) Thread类的构造方法


1. Thread类直接构造一个新的线程对象

方法说明
public Thread()分配一个新的线程对象。
public Thread(String name)分配一个指定名字的新的线程对象。

2. 用Runnable接口的实现类来改造新的线程对象

2.1构造方法

方法说明
public Thread(Runnable target)分配一个带有指定目标新的线程对象
public Thread(Runnable target,String name) :分配一个带有指定目标新的线程对象并指定名字

2.2步骤

       (1)定义Runnable接口的实现类,并重写该接口的run()方法,该run()方法的方法体同样是该线程的线程执行体。

       (2)创建Runnable实现类的实例,并以此实例作为Thread的target来创建Thread对象,该Thread对象才是真正的线程对象。

       (3)调用线程对象的start()方法来启动线程。

2.3 Runnable接口的优点

       (1)用Thread类直接构造新线程,有单继承的局限性,而Runnable接口的实现类可以实现多个接口,也可以再继承一个类。

       (2)多个线程可以共享同一个资源,传入同一个Runnable的实现类。

       (3)增强了程序的扩展性,降低了程序的耦合性。设置线程任务和开启新线程进行了分离。Runnable接口的实现类中重写了run()方法,用来设置线程任务;在创建新线程时,创建Thread类对象,调用start()方法,用来开启新线程,二者是分离的。

       (4)线程池只能放入实现Runable或Callable类线程,不能直接放入继承Thread的类。


(三) Thread类的常用方法


方法说明
public String getName()获取当前线程名称。
public void start()导致此线程开始执行; Java虚拟机调用此线程的run方法。
public void run()此线程要执行的任务在此处定义代码。
public static void sleep(long millis)使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行)
public static Thread currentThread()返回对当前正在执行的线程对象的引用。

(四) 匿名内部类创建线程


       使用匿名内部类的方式,可以快速地创建新线程。

1. 创建Thread类的匿名内部类

//Thread()
new Thread(){
    @Override
    public void run() {
        for(int i = 0 ; i < 20; ++i){
            System.out.println(Thread.currentThread().getName() + i);
        }
    }
}.start();

2. 创建Runnable接口的匿名内部类

//Runnable
new Thread(new Runnable() {
    @Override
    public void run() {
        for(int i = 0; i <10; ++i){
            System.out.println(i);
        }
    }
}).start();

二. 线程安全


(一) 概述

       线程安全问题一般由全局变量和静态变量引起,若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作,一般都需要考虑线程同步,否则的话就可能影响线程安全。

(二) 线程同步

       要解决多线程并发访问同一个资源的安全性问题,就要用到同步机制(synchronized)。

1. 同步代码块

       将synchronized关键字用于某个块代码中,表示只对这个块代码进行互斥访问。

(1) 格式:
synchronized(同步锁){
     需要同步操作的代码
}

(2) 同步锁

       同步锁的类型可以是任意类型,谁拿到了这个锁,谁就能够进入代码块执行代码,而其他没有拿到锁的线程只能等待(BLOCKED)。多个线程使用的是同一把锁。

2. 同步方法

       用synchronized关键字修饰的方法称为同步方法。

(1) 格式
public synchronized void method(){
   可能会产生线程安全问题的代码 
}

(2) 同步锁

       对于非static方法,同步锁是this,即调用该方法的对象。
       对于static方法,同步锁是调用该方法所在类的字节码对象。(类名.class)。

3. Lock锁

       更加广泛的锁操作,将加锁和释放锁都变成了方法:

public void lock() :加同步锁。
public void unlock() :释放同步锁。

       在需要加锁的代码前加锁,在代码后释放锁。

三. 线程状态


(一) 六种状态


线程状态导致状态发生条件
NEW(新建)线程刚被创建,但是并未启动。还没调用start方法。
Runnable(可运行)线程可以在java虚拟机中运行的状态,可能正在运行自己代码,也可能没有,这取决于操作系统处理器。
Blocked(锁阻塞)当一个线程试图获取一个对象锁,而该对象锁被其他的线程持有,则该线程进入Blocked状态;当该线程持有锁时,该线程将变成Runnable状态。
Waiting(无限等待)一个线程在等待另一个线程执行一个(唤醒)动作时,该线程进入Waiting状态。进入这个状态后是不能自动唤醒的,必须等待另一个线程调用notify或者notifyAll方法才能够唤醒。
Timed Waiting(计时等待)同waiting状态,有几个方法有超时参数,调用他们将进入Timed Waiting状态。这一状态将一直保持到超时期满或者接收到唤醒通知。带有超时参数的常用方法有Thread.sleep 、Object.wait。
Teminated(被终止)因为run方法正常退出而死亡,或者因为没有捕获的异常终止了run方法而死亡。

(二) Time Waiting

       计时等待,可以通Thread.sleep,Object.wait进入线程的等待,并自动唤醒或者受到唤醒通知。

       Sleep与锁无关,线程等待到期自动唤醒,返回到Runnable状态。注意,sleep()中指定的时间是线程等待的最短时间,并不能保证该时间到期就一定唤醒。

(三) BLOCKED

       没有争取到锁对象的线程进入阻塞状态,等待锁对象。

(四) Waiting

       无限等待状态,调用了Object.wait方法只能等待另一个线程调用该对象的Object.notify()方法或者Object.notifyAll()方法唤醒。被唤醒后的线程如果没有锁对象,就会处于BLOCKED状态,有了锁对象,才是Runnable状态。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值