浅析线程及同步

守护线程

通常情况下 后台的应用程序就是守护程序 被守护的线程结束了即使守护的线程没有结束那么也将会结束

线程的局部变量:解决多线程共享同个对象的时候,对象属性数据安全问题

ThreadLocal通过get获取

线程池:线程的容器可以帮助我们进行线程的创建。ExecutorService

说明:线程类,创建线程的主要类

Thread currentThread() 获取当前代码所在的线程对象

String getName() 获取线程的名称

主线程名:main

子线程名:Thread-编号,编号从0开始

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

long  getId() 获取线程的id

boolean isAlive() 是否处于活动状态

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

Thread.State.NEW 创建状态

Thread.State.RUNNABLE 就绪状态-可运行状态

Thread.State.TERMINATED 结束状态

Thread.State.BLOCKED 阻塞状态

Thread.State.TIMED_WAITING 休眠状态

Thread.State.WAITING 等待状态

阻塞状态

主线程名:main

子线程名:Thread-编号,编号从0开始

Thread.State.NEW 创建状态

Thread.State.RUNNABLE 就绪状态-可运行状态

Thread.State.TERMINATED 结束状态

Thread.State.BLOCKED 阻塞状态

Thread.State.TIMED_WAITING 休眠状态

Thread.State.WAITING 等待状态

void setDaemon(boolean?on) 将该线程标记为守护(后台)线程或用户线程

Thread.sleep(long millis) 将线程转入等待状态(TIMED_WATING)

Thread.yield() 线程让步,把执行机会让给相同或者更高优先级的线程,但随后仍然可能继续执行

void join() 线程加入,当前线程进入WAITING状态,当被调用的线程运行结束,则当前线程再转为Runnable状态

void setPriority(int newPriority) 设置优先级

int getPriority() 获取优先级

Runnable接口

说明:线程体接口,只拥有线程执行的任务,不具有线程功能

作用:为相同程序代码的多个线程提供共享的数据

public void run() 抽象方法

说明:线程体接口,只拥有线程执行的任务,不具有线程功能

作用:为相同程序代码的多个线程提供共享的数据

public void run() 抽象方法

1、一个进程中的每个线程都在栈中有一块自己的内存

多线程与栈

1、一个进程中的每个线程都在栈中有一块自己的内存

2、只有当线程执行完自己的任务代码时,才会释放自己所占的内存

3、只有当进程中的所有线程结束了,该进程才结束

2、只有当线程执行完自己的任务代码时,才会释放自己所占的内存

3、只有当进程中的所有线程结束了,该进程才结束

线程加锁

使用notify的时候一定要注意使用的是while 要不会出现错误

synchronized 采用的是悲观锁

lock 乐观锁 。

synchronized(对象){}

使用之后就会释放锁

使用lock接口对锁进行了单独的描述

创建一个lock的子类reentrantlock

使用lock替代我们的同步代码块

需要同步的代码放入lock和unlock、之间

condition 使用的是await() signal() signalAll()

说明:用于解决线程间共享数据时存在的安全问题

互斥锁

作用:在Java中引入对象互斥锁的概念,保证共享数据操作的完整性

说明:每个对象都对应于一个可称为"互斥锁"的标记,这个标记保证在任一时刻,只能有一个线程访问对象

关键字:synchronized,用来给对象加互斥锁

解决方式

当一个线程得到cpu,执行操作共享数据的多条语句时,其它线程不能参与执行,只有该线程把所有操作共享数据的语句全部执行完,其它线程才能参与执行

自由主题

当一个线程得到cpu,执行操作共享数据的多条语句时,其它线程不能参与执行,只有该线程把所有操作共享数据的语句全部执行完,其它线程才能参与执行

线程同步

说明:用于解决线程间共享数据时存在的安全问题

互斥锁

作用:在Java中引入对象互斥锁的概念,保证共享数据操作的完整性

说明:每个对象都对应于一个可称为"互斥锁"的标记,这个标记保证在任一时刻,只能有一个线程访问对象

关键字:synchronized,用来给对象加互斥锁

三种加锁方式

1、同步非静态方法

格式:public synchronized void method1(){}

说明:synchronized放在方法声明中,表示整个方法为同步方法,锁定this对象

如果有一个线程进入了该方法,其他线程要想使用当前this对象的任何同步方法,都必须等待前一个线程执行完该同步方法之后

2、同步static方法

格式:public synchronized static void method1()

说明: synchronized放在static方法声明中,表示锁定该类的class对象

如果有一个线程进入了该方法,其他线程要想使用当前类中的任何同步静态方法,都必须等待前一个线程执行完该同步方法之后;其他非同步方法及非静态的同步方法的执行不受影响

3、同步代码块

同步this:

synchronized(this){//this被加锁,任何其他要锁this的代码块被阻塞.

需要同步的代码;

}

同步obj:

synchronized(obj){//obj被加锁,任何其他要锁obj的代码块被阻塞.

需要同步的代码;

}

说明:synchronized放在对象前面限制一段代码的执行

线程同步的弊端

不能进入同步代码块的线程会反复的判读锁,降低了程序的性能

使用同步需要满足的条件

1、同步中至少有两个线程

2、使用同一把锁

避免死锁

由于线程1锁住资源A等待资源B,线程2锁住资源B等待资源A,两个线程都在等待自己需要的资源,而这些资源被另外的线程锁住,这些线程你等我,我等你,谁也不愿意让出资源,这样死锁就产生了

三种加锁方式

1、同步非静态方法

格式:public synchronized void method1(){}

说明:synchronized放在方法声明中,表示整个方法为同步方法,锁定this对象

如果有一个线程进入了该方法,其他线程要想使用当前this对象的任何同步方法,都必须等待前一个线程执行完该同步方法之后

2、同步static方法

格式:public synchronized static void method1()

说明: synchronized放在static方法声明中,表示锁定该类的class对象

如果有一个线程进入了该方法,其他线程要想使用当前类中的任何同步静态方法,都必须等待前一个线程执行完该同步方法之后;其他非同步方法及非静态的同步方法的执行不受影响

3、同步代码块

同步this:

synchronized(this){//this被加锁,任何其他要锁this的代码块被阻塞.

需要同步的代码;

}

同步obj:

synchronized(obj){//obj被加锁,任何其他要锁obj的代码块被阻塞.

需要同步的代码;

}

说明:synchronized放在对象前面限制一段代码的执行

线程同步的弊端

不能进入同步代码块的线程会反复的判读锁,降低了程序的性能

使用同步需要满足的条件

1、同步中至少有两个线程

2、使用同一把锁

避免死锁

由于线程1锁住资源A等待资源B,线程2锁住资源B等待资源A,两个线程都在等待自己需要的资源,而这些资源被另外的线程锁住,这些线程你等我,我等你,谁也不愿意让出资源,这样死锁就产生了

线程之间的通信:

说明:多个线程执行的任务不同,但是操作的资源是相同的

生产者消费者模式

生产者(Producer)与消费者(Consumer)的问题

生产者将产品交给店员(Clerk),而消费者从店员处取走产品,店员一次只能持有固定数量的产品,如果生产者生产了过多的产品,店员叫生产者等一下,如果店中有空位放产品了再通知生产者继续生产;如果店中没有产品了,店员会告诉消费者等一下,如果店中有产品了再通知消费者来取走产品。

生产者(Producer)与消费者(Consumer)的问题

生产者将产品交给店员(Clerk),而消费者从店员处取走产品,店员一次只能持有固定数量的产品,如果生产者生产了过多的产品,店员叫生产者等一下,如果店中有空位放产品了再通知生产者继续生产;如果店中没有产品了,店员会告诉消费者等一下,如果店中有产品了再通知消费者来取走产品。

理解等待与唤醒

Object类中的wait() 导致当前的线程等待,直到其他线程调用此对象的notify()方法或notifyAll() 唤醒方法

线程等待

Object类中的wait() 导致当前的线程等待,直到其他线程调用此对象的notify()方法或notifyAll() 唤醒方法

Object 类中的notify()方法,唤醒在此对象监视器上等待的单个线程。如果所有线程都在此对象上等待,则会选择唤醒其中一个线程。选择是任意性的。

线程唤醒

Object 类中的notify()方法,唤醒在此对象监视器上等待的单个线程。如果所有线程都在此对象上等待,则会选择唤醒其中一个线程。选择是任意性的。

Object类中的notifyAll()方法,唤醒在此对象监视器上等待的所有线程。

Object类中的notifyAll()方法,唤醒在此对象监视器上等待的所有线程。

注意:wait()、notify()和notifyAll()三个方法只能在被同步化(synchronized)的方法或代码块中调用

线程的停止:

1、如果线程的run()方法中执行的是一个重复执行的循环,可以提供一个“标记”来控制循环是否继续执行

2、对于正在执行的线程,interrupt()无法打断该线程的执行,但是可以获得该线程被中断的标志: Thread.interrupted()得到true,调用后,中断标志将被清除(变为false)

3、如果线程因为执行join(),sleep()或是wait()而进入了阻塞状态,此时要想停止它,可以使用interrupt(),程序会抛出InterruptException异常而被catch()子句捕获,进行处理

4、如果程序因为输入/输出的等待而阻塞,基本上必须等待输入/输出的动作完成才能离开阻塞状态。无法用interrupt()方法来使得线程离开run()方法,要想离开,只能通过引发一个异常。

对于锁的操作:

jdk1.5之前对锁的操作是隐式的

synchronized(对象)//获取锁

{

需要同步的代码

}//释放锁

jdk1.5使用Lock接口对锁进行的单独的描述---面向对象

自由主题

Lock接口

说明:JDK1.5提供的同步锁操作接口

Condition newCondition() 获取锁的情况,便于操作线程的状态或条件

lock() 获取锁

unlock() 释放锁

synchronized(对象)//获取锁

{

需要同步的代码

}//释放锁

涉及核心接口与类

Lock接口

说明:JDK1.5提供的同步锁操作接口

Condition newCondition() 获取锁的情况,便于操作线程的状态或条件

lock() 获取锁

unlock() 释放锁

ReentrantLock类

接口Lock的实现类

int getHoldCount()

int  getQueueLength()

int getWaitQueueLength(Condition condition)

boolean hasQueuedThreads() 判断锁的等待池中是否存在多个线程

boolean hasWaiters(Condition c) 判断锁的等待池中包含condition条件的线程

Conditon接口

说明:提供锁所在线程的状态操作,如等待与唤醒

await() 等待

signal() 唤醒

signalAll() 唤醒所有

ReentrantLock类

接口Lock的实现类

int getHoldCount()

int  getQueueLength()

int getWaitQueueLength(Condition condition)

boolean hasQueuedThreads() 判断锁的等待池中是否存在多个线程

boolean hasWaiters(Condition c) 判断锁的等待池中包含condition条件的线程

Conditon接口

说明:提供锁所在线程的状态操作,如等待与唤醒

await() 等待

signal() 唤醒

signalAll() 唤醒所有

1、创建Lock的子类对象

2、调用Lock对象的newCondition()创建线程状态控制对象

3、把需要同步的代码放在lock()和unlock()之间

使用步骤

1、创建Lock的子类对象

2、调用Lock对象的newCondition()创建线程状态控制对象

3、把需要同步的代码放在lock()和unlock()之间

4、在用到wait()、notify()等地方,改换成Condition对象的相关方法

注意

1、多个线程之间只能存在一个Lock对象

2、为了避免死锁,一般将解锁位置放在finally语句中

3、对于wait-notify状态转换应该产生两个Condition对象进行控制

4、在用到wait()、notify()等地方,改换成Condition对象的相关方法

注意

1、多个线程之间只能存在一个Lock对象

2、为了避免死锁,一般将解锁位置放在finally语句中

3、对于wait-notify状态转换应该产生两个Condition对象进行控制

线程的局部变量:

涉及的类:java.lang.ThreadLocal

作用:用于解决多个线程共享同一个对象时,对象属性的数据安全问题.

1) 每一个ThreadLocal对象就像一个整个楼的信箱,每一个线程只能打开其中的一个属于自己的信箱.这个信箱只能放一个对象.

说明

1) 每一个ThreadLocal对象就像一个整个楼的信箱,每一个线程只能打开其中的一个属于自己的信箱.这个信箱只能放一个对象.

2)本质上ThreadLocal类中有一个Map,用于存储每一个线程的变量的副本.且无需知道key是什么(其实是当前线程).也不会错用到其他线程的局部变量.

2)本质上ThreadLocal类中有一个Map,用于存储每一个线程的变量的副本.且无需知道key是什么(其实是当前线程).也不会错用到其他线程的局部变量.

后台守护线程:

说明:在后台运行的线程,为其他的线程提供服务

设置方法:setDaemon(boolean b) 把一个线程设置成后台线程

1、经常用于任务结束时的善后处理,典型的后台线程是定时器Timer线程

作用

1、经常用于任务结束时的善后处理,典型的后台线程是定时器Timer线程

2、后台线程的优先级比其他线程的低

3、如果没有“用户线程”在运行,JVM将退出,守护线程将被自动终止

2、后台线程的优先级比其他线程的低

3、如果没有“用户线程”在运行,JVM将退出,守护线程将被自动终止

多线程编程一般规则

1、如果两个或两个以上的线程都修改一个对象,那么把执行修改的方法定义为被同步的,如果对象更新影响到只读方法,那么只读方法也要定义成同步的。

2、不要滥用同步。如果在一个对象内的不同的方法访问的不是同一个数据,就不要将方法设置为synchronized的

3、如果一个线程必须等待一个对象状态发生变化,那么他应该在对象内部等待,而不是在外部。他可以通过调用一个被同步的方法,并让这个方法调用wait()。

4、每当一个方法返回某个对象的锁时,它应当调用notifyAll()来让等待队列中的其他线程有机会执行。

5、记住wait()和notify()/notifyAll()是Object类方法,而不是Thread类的方法。仔细查看每次调用wait()方法,都有相应的notify()/notifyAll()方法,且它们均作用于同一个对象。

多线程编程一般规则:

1、如果两个或两个以上的线程都修改一个对象,那么把执行修改的方法定义为被同步的,如果对象更新影响到只读方法,那么只读方法也要定义成同步的。

2、不要滥用同步。如果在一个对象内的不同的方法访问的不是同一个数据,就不要将方法设置为synchronized的

3、如果一个线程必须等待一个对象状态发生变化,那么他应该在对象内部等待,而不是在外部。他可以通过调用一个被同步的方法,并让这个方法调用wait()。

4、每当一个方法返回某个对象的锁时,它应当调用notifyAll()来让等待队列中的其他线程有机会执行。

5、记住wait()和notify()/notifyAll()是Object类方法,而不是Thread类的方法。仔细查看每次调用wait()方法,都有相应的notify()/notifyAll()方法,且它们均作用于同一个对象。

static void sleep (Long毫秒)制定的毫秒之内使运行的线程睡眠

会抛出异常 Throws InterruptedException() 线程休眠是帮助所有线程获得资源的最好的方法

线程睡眠之后自动苏醒,返回到就绪状态不是运行状态

sleep指定的时间是休眠之后可运行的最短的时间不能保证到期之后就开始运行

是静态的方法智能控制当前的线程

线程的优先级,级别越高机会越多,级别越低机会越少不绝对

最大是10 最小是1 默认是5

使用setPriority()

getPriority()

线程的join()方法线程的合并 当前线程等待该线程执行完毕

static yield(0当前线程让步只会让步一次下一次是哪个线程是不一定了

线程的中断的方法

interrupt()线程的中断的方法更改了中断的标志false--》true

static boolean interrupted() 是否被中断的状态 返回的就是flag 但是有一个查除的方法

实现的原理是什么就是锁定一个对象

实现同步的方式:同步代码块 synchronized(锁){}方法代码执行完成后自动解锁,可以使任意的对象Object obj = new Object

synchronized()

this 锁住当前的对象把当前的对象声明成一个锁

可以锁住一个字符串

运行时的锁

静态的数据调用的时候使用的是运行时的锁

同步的方法 在方法的前面加上synchronized

同步静态方法锁定的是this对象

同步静态方法锁定的是XXX.class

多线程需要同步机制

数据安全 :

采用同步代码块的方式 synchronized(){}

类型可以是任意的对象

当前的对象this 同时可以是静态的对象

还有一种采用同步方法注意方法的粒度

多线程共享数据的时候多条,一个线程执行操作共享数据如果还没执行完成,就被其他的线程抢占到CPU那么这个过程中就会出现数据不安全一个得到CPU那么其他的CPU就只能等待直到该线程执行完成为止。

使用同步代码块的好处就是:将共享数据放到里面,但是降低了性能需要不断的访问看看是不是锁已经被释放。

使用同步时候满足条件:

至少两个线程

使用同一把锁

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-12-28 08:46:22

浅析线程及同步的相关文章

Linux环境下线程消息同步的陷阱

我们程序中常常会使用到线程间的消息同步处理,比如以下一段伪码 var message = "": void func()  {   1. 启动线程Thread(该线程中填充message的内容):   2. 阻塞,直到等待到完成message填充的事件:   3. 处理message:   .... } void Thread()  {   1. 通过某种处理填充message:   2. 触发func中的阻塞事件: } 我们通常会使用条件变量来完成类似情况的线程同步处理 比如wind

线程+任务+同步

线程: 对于所有需要等待的操作,例如移动文件,数据库和网络访问都需要一定的时间,此时就可以启动一个新的线程,同时完成其他任务.一个进程的多个线程可以同时运行在不同的CPU上或多核CPU的不同内核上. 线程是程序中独立的指令流.在VS编辑器中输入代码的时候,系统会分析代码,用下划线标注遗漏的分号和其他语法错误,这就是用一个后台线程完成.Word文档需要一个线程等待用户输入,另一个线程进行后台搜索,第三个线程将写入的数据存储在临时文件中.运行在服务器上的应用程序中等待客户请求的线程成为侦听器线程.

线程间同步之信号量实现环形buf

一.概述: 信号量是一个非负整数的计数器,它通过计数器来实现多线程对临界资源的顺序访问,从而实现线程间的同步.它与进程间通信的信号量不同,进程间通信的信号量是一个信号量集,而线程间同步的信号量是一个信号.还有一点,就是对信号量的操作是原子的. 信号量与互斥锁的区别: (1).互斥锁的值只能是0或1,而信号量的值为非负整数. (2).互斥锁用与实现线程间的互斥,而信号量用于实现线程间的同步. (3).互斥锁的加锁和解锁必须由同一个线程分别对应使用,而信号量可以由一个线程得到,另一个线程释放. 下面

线程的同步与互斥,死锁

线程的同步与互斥 多个线程同时访问共享数据时可能会发生冲突,比如两个线程同时把一个全局变量加1,结果可能不是我们所期待的: 我们看这段代码的执行结果: #include <stdio.h> #include <stdlib.h> #include <pthread.h> static int g_count=0; void *thread(void *arg) { int index=0; int tmp=0; while(index++<5000) { tmp=

线程和同步

线程和同步 1 概述 对于所有需要等待 的操作,例 如 ,因 为文件 . 数据库或网络访 问都需要一定 的时间,此 时就可以启 动一个新线程,同时完成其他任务,即使是处理密集型的任务,线程也是有帮助的. 2 Parallel类 2.1 用Parallel.For()方法循环 Parallel.For()方法类似于C#的For循环,多次执行一个任务,它可以并行运行迭代.迭代的顺序没有定义. 1 ParallelLoopResult result = Parallel.For(0, 10, i =>

浅析线程间通信三:Barriers、信号量(semaphores)以及各种同步方法比较

之前的文章讨论了互斥量.条件变量.读写锁和自旋锁用于线程的同步,本文将首先讨论Barriers和信号量的使用,并给出了相应的代码和注意事项,相关代码也可在我的github上下载,然后对线程各种同步方法进行了比较. Barriers Barriers是一种不同于前面线程同步机制,它主要用于协调多个线程并行(parallel)共同完成某项任务.一个barrier对象可以使得每个线程阻塞,直到所有协同(合作完成某项任务)的线程执行到某个指定的点,才让这些线程继续执行.前面使用的pthread_join

第二十八(线程的同步、守护线程、Timer 定时器)

/* 模拟ATM取款,不是线程同步机制,多线程同时对一个账户进行操作 t1 和 t2 异步编程模型:t1线程执行t1,t2线程执行的是t2,两个线程之间谁也不等于谁 同步编程模型:t1线程和t2线程执行,当t1线程必须等于t2的线程执行结果之后,t1线程才能执行 这是同步编程模型. 什么时候需要引入同步 1. 为了数据安全,尽管应用程序的使用率低,但是为了保证数据安全性,必须的加入线程同步机制 线程同步机制 使程序变成了(等同)单线程 2. 在什么条件下需要使用线程同步 <1> 必须是多线程环

Java线程:线程的同步与锁

一.同步问题提出 线程的同步是为了防止多个线程访问一个数据对象时,对数据造成的破坏. 例如:两个线程ThreadA.ThreadB都操作同一个对象Foo对象,并修改Foo对象上的数据. public class Foo {     private int x = 100; public int getX() {         return x;     } public int fix(int y) {         x = x - y;         return x;     } }

线程的同步synchronized

一个Java程序的多线程之间可以共享数据. 当线程以异步方式访问共享数据时,有时候是不安全的或者不和逻辑的.比如卖火车票,同一时刻一个线程在读取数据,另外一个线程在处理数据,当处理数据的线程没有等到读取数据的线程读取完毕就去处理数据,必然得到错误的处理结果. 卖火车票Demo: class MyThread implements Runnable{ private int ticket = 5 ; // 假设一共有5张票 public void run(){ for(int i=0;i<100;