线程(有同步锁和死锁)

线程(有同步锁和死锁)
2.1 概述
进程
在操作系统中运行的程序
线程
线程是进程的一个 执行单元, 一条执行路径
如: 360安全卫士就是一个进程, 其中电脑体检/木马查杀/电脑清理等就是该进程的执行单元
多线程:
一个进程至少有一个线程
如果进程有多个执行路径,它就是多线程应用程序
注意:
操作系统是以进程为单位分配系统资源(主要是指CPU资源)
如果进程有多个线程, 这些线程共享该进程的资源
每个线程都有独立的栈空间, 共享堆区与方法区

主线程
	JVM启动的主线程,主线程执行main方法
用户线程
	程序员开启的新的线程,也称子线程
守护线程
	为其他线程提供服务的线程. 如垃圾回收器
	当JVM中只有守护线程时, JVM就退出,  守护线程不能单独执行

2.2创建线程的方式
Thread类

2.2.1 定义类继承Thread
class SubThread extends Thread{
public void run(){
子线程要执行的代码
}
}
Subthread t1 = new SubThread();
t1.start();

2.2.2 定义Runnable接口的实现类
class Prime1 implements Runnable{
public void run(){
子线程执行的代码
}
}
Thread t2 = new Thread( new Prime1() );
t2.start();

2.2.3 定义Callable接口的实现类
class Prime2 implements Calllable {
public Integer call() throws Exception{
子线程执行的代码
return xxx;
}
}

Prime2  p = new Prime2();
FutureTask<Integer>  task = new FutureTask<>(  p  );
Thread  t3 = new Thread( task); 
t3.start();
//在主线程中获得子线程的返回值
Integer  i1  = task.get();

2.3 线程的常用方法
static int activeCount() 返回活动线程的数量.

static Thread
currentThread() 返回当前线程

ClassLoader
getContextClassLoader() 返回线程上下文类加载器.

long getId() 返回线程的ID,每个线程都有唯一的Id.

String
getName() 返回线程的名称

int getPriority() 线程优先级

Thread.State
getState() 返回线程的状态.

void interrupt() 中断线程.

static boolean interrupted() 判断线程的中断标志.

boolean isAlive() 判断线程是否结束 .

boolean isDaemon() 判断是否为守护线程

boolean isInterrupted() 判断线程是否被中断.

void join() 线程加入,线程合并

void join(long millis)

void run() 线程要执行的代码

void setDaemon(boolean on) 设置线程为守护线程.

void setName(String name)设置线程名称.

void setPriority(int newPriority) 设置优先级

static void sleep(long millis) 线程休眠.

void start() 开启新的线程

void stop() 终止线程的执行

String
toString().

static void yield() 线程让步

2.4 线程的生命周期
线程的状态图

类锁:当前类的运行时类作为锁对象。
2.5 线程调度
2.5.1 优先级
取值范围:1~10
默认值: 5
优先级越高获得CPU执行权的机率越大
2.5.2 睡眠
Thread.sleep( millis )
静态方法,通过类名直接调用
单位是毫秒
有受检异常需要处理
所在的方法进行睡眠 (休眠)
2.5.3 中断
t1.interrupt(); 中断线程
一般把睡眠/等待中的线程给中断,
t1.isInterrupted() 判断线程的中断状态, 返回true后,不会清除中断标志
Thread.interrupted(), 判断线程中断状态为true后,会清除中断标志
2.5.4 线程合并
t1.join(); 在当前线程中加入t1线程, 当前线程转为等待状态, 一直等到t1线程执行完后再转为就绪状态
2.5.5 线程让步
Thread.yield() 是把线程转为就绪状态, 重新争抢CPU执行权
2.5.6 线程终止
t1.stop()
一般 通过修改线程标志的方式来结束 线程

2.6 线程同步
2.6.1 同步代码块语法
1) 什么是线程安全问题?
当多个线程同时操作堆区/方法区中同一个数据时, 产生的数据不一致的现象,称为线程安全问题
2) 出现了线程安全问题,怎么办?
避免出现多个线程操作同一个数据,每个 线程都操作自己的局部变量
如果必须操作同一个数据, 进行线程同步
3)如何线程同步?
synchronized( 锁对象 ){
同步代码块
}
4)线程同步的工作原理是什么 ?
(1)线程要执行同步代码块,必须先获得锁对象(获得对象的锁)
(2)任意对象都可以作为锁对象
(3)锁对象最多只能由一个线程持有
(4)线程持有了锁对象会一直持有,直到执行完同步代码块再释放

5) 线程同步过程的描述

2.6.2 同步代码块
线程要实现同步,必须使用同一个锁对象
同步代码块只要使用了同一个锁对象就可以实现线程同步

2.6.3 同步方法
直接使用synchronized关键字修饰的方法就是同步方法, 整个方法体作为同步代码块

synchronized修饰实例方法, 默认的锁对象是this对象
synchronized修饰静态方法, 默认的锁对象是当前类的运行时类对象,  Test03.class 

2.6.4死锁
当开发多线程程序,需要进行同步, 并且 需要多个 锁对象时,
如果线程获得锁对象的顺序不一样, 可能导致线程出现相互等待的情况, 称之为死锁现象
死锁的解决方法:
保证锁对象的顺序一致即可
Set daemon(true)代码块,用户线程变成守护线程

总结

代码:
IO+Properties读取配置文件
创建线程的各种方式
常用方法, 记住什么方法什么功能即可, 代码是为说明知识点的, 掌握通过标志结束线程的代码
线程同步的代码

线程安全就是多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用。不会出现数据不一致或者数据污染。 线程不安全就是不提供数据访问保护,有可能出现多个线程先后更改数据造成所得到的数据是脏数据

概念:
如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。
或者说:一个类或者程序所提供的接口对于线程来说是原子操作或者多个线程之间的切换不会导致该接口的执行结果存在二义性,也就是说我们不用考虑同步的问题。
线程安全问题都是由全局变量及静态变量引起的。
若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作,一般都需要考虑线程同步,否则的话就可能影响线程安全。
安全性:
比如一个 ArrayList 类,在添加一个元素的时候,它可能会有两步来完成:1. 在 Items[Size] 的位置存放此元素;2. 增大 Size 的值。在单线程运行的情况下,如果 Size = 0,添加一个元素后,此元素在位置 0,而且 Size=1;而如果是在多线程情况下,比如有两个线程,线程 A 先将元素存放在位置 0。但是此时 CPU 调度线程A暂停,线程 B 得到运行的机会。线程B也向此 ArrayList 添加元素,因为此时 Size 仍然等于 0 (注意哦,我们假设的是添加一个元素是要两个步骤哦,而线程A仅仅完成了步骤1),所以线程B也将元素存放在位置0。然后线程A和线程B都继续运行,都增加 Size 的值。那好,我们来看看 ArrayList 的情况,元素实际上只有一个,存放在位置 0,而 Size 却等于 2。这就是“线程不安全”了。安全性:
线程安全性不是一个非真即假的命题。 Vector 的方法都是同步的,并且 Vector 明确地设计为在多线程环境中工作。但是它的线程安全性是有限制的,即在某些方法之间有状态依赖(类似地,如果在迭代过程中 Vector 被其他线程修改,那么由 Vector.iterator() 返回的 iterator会抛出ConcurrentModifiicationException)。对于 Java 类中常见的线程安全性级别,没有一种分类系统可被广泛接受,不过重要的是在编写类时尽量记录下它们的线程安全行为。Bloch 给出了描述五类线程安全性的分类方法:不可变、线程安全、有条件线程安全、线程兼容和线程对立。只要明确地记录下线程安全特性,那么您是否使用这种系统都没关系。这种系统有其局限性 – 各类之间的界线不是百分之百地明确,而且有些情况它没照顾到 – 但是这套系统是一个很好的起点。这种分类系统的核心是调用者是否可以或者必须用外部同步包围操作(或者一系列操作)。下面几节分别描述了线程安全性的这五种类别。不可变不可变的对象一定是线程安全的,并且永远也不需要额外的同步[1] 。因为一个不可变的对象只要构建正确,其外部可见状态永远也不会改变,永远也不会看到它处于不一致的状态。Java 类库中大多数基本数值类如 Integer 、 String 和 BigInteger 都是不可变的。需要注意的是,对于Integer,该类不提供add方法,加法是使用+来直接操作。而+操作是不具线程安全的。这是提供原子操作类AtomicInteger的原。线程安全线程安全的对象具有在上面“线程安全”一节中描述的属性 – 由类的规格说明所规定的约束在对象被多个线程访问时仍然有效,不管运行时环境如何排线程都不需要任何额外的同步。这种线程安全性保证是很严格的 – 许多类,如 Hashtable 或者 Vector 都不能满足这种严格的定义。
有条件的有条件的线程安全类对于单独的操作可以是线程安全的,但是某些操作序列可能需要外部同步。条件线程安全的最常见的例子是遍历由 Hashtable 或者 Vector 或者返回的迭代器 – 由这些类返回的 fail-fast 迭代器假定在迭代器进行遍历的时候底层集合不会有变化。为了保证其他线程不会在遍历的时候改变集合,进行迭代的线程应该确保它是独占性地访问集合以实现遍历的完整性。通常,独占性的访问是由对锁的同步保证的 – 并且类的文档应该说明是哪个锁(通常是对象的内部监视器(intrinsic monitor))。如果对一个有条件线程安全类进行记录,那么您应该不仅要记录它是有条件线程安全的,而且还要记录必须防止哪些操作序列的并发访问。用户可以合理地假设其他操作序列不需要任何额外的同步。线程兼容线程兼容类不是线程安全的,但是可以通过正确使用同步而在并发环境中安全地使用。这可能意味着用一个 synchronized 块包围每一个方法调用,或者创建一个包装器对象,其中每一个方法都是同步的(就像 Collections.synchronizedList() 一样)。也可能意味着用 synchronized 块包围某些操作序列。为了最大程度地利用线程兼容类,如果所有调用都使用同一个块,那么就不应该要求调用者对该块同步。这样做会使线程兼容的对象作为变量实例包含在其他线程安全的对象中,从而可以利用其所有者对象的同步。许多常见的类是线程兼容的,如集合类 ArrayList 和 HashMap 、 java.text.SimpleDateFormat 、或者 JDBC 类 Connection 和 ResultSet 。线程对立线程对立类是那些不管是否调用了外部同步都不能在并发使用时安全地呈现的类。线程对立很少见,当类修改静态数据,而静态数据会影响在其他线程中执行的其他类的行为,这时通常会出现线程对立。线程对立类的一个例子是调用 System.setOut() 的类。

/**
死锁

/
package com.bjpowernode.demo06;

public class SubThread extends Thread{
@Override
public void run() {
if (“a”.equals( Thread.currentThread().getName() )) {
synchronized (“资源1”) {
System.out.println(“线程a锁住了资源1, 还想获得资源2”);
synchronized (“资源2”) {
System.out.println("线程a同时获得了资源1与资源2,可以做爱做的事 ");
}
}
}

  if ("b".equals( Thread.currentThread().getName() )) {
     synchronized ("资源2") {
        System.out.println("线程b锁住了资源2, 还想获得资源1");
        synchronized ("资源1") {
           System.out.println("线程b同时获得了资源1与资源2,可以做爱做的事 ");
        }
     }
  }

}
}

package com.bjpowernode.demo06;
/**

  • 死锁
  • @author Administrator

*/
public class Test {

public static void main(String[] args) {
SubThread t1 = new SubThread();
t1.setName(“a”);
t1.start();

  SubThread t2 = new SubThread();
  t2.setName("b");
  t2.start();

}

}

猜你喜欢

转载自blog.csdn.net/qq_30347133/article/details/83515581