JAVA高并发处理------多线程

时间:2021-12-09 17:59:30

线程安全概念:当多个线程访问某一个类(对象或方法)时,这个对象始终都能表现出正确的行为,那么这个类(对象或方法)就是线程安全的。

分析:当多个线程访问myThread的run方法时,以排队的方式进行处理(这里排对是按照CPU分配的先后顺序而定的),一个线程想要执行synchronized修饰的方法里的代码:1 尝试获得锁  2 如果拿到锁,执行synchronized代码体内容;拿不到锁,这个线程就会不断的尝试获得这把锁,直到拿到为止,而且是多个线程同时去竞争这把锁。(也就是会有锁竞争的问题)

synchronized:可以在任意对象及方法上加锁,而加锁的这段代码称为"互斥区"或"临界区"。取得的锁都是对象锁,而不是把一段代码(方法)当做锁,所以代码中哪个线程先执行synchronized关键字的方法,哪个线程就持有该方法所属对象的锁(Lock),在静态方法上加synchronized关键字,表示锁定.class类,类一级别的锁(独占.class类)。

锁对象的改变问题:例如下面代码中,当lock发生变化后,t1开始后,t2直接开始。如果去掉将lock改变的代码,则是t1结束后t2才会开始。但是同一对象属性的修改不会影响锁的情况,比如下面代码的lock现在是一个带属性的对象,如果改变该对象的属性,结果还是t1结束后t2才会开始。

package com.bjsxt.base.sync006;
/**
* 锁对象的改变问题
*
@author alienware
*
*/
public class ChangeLock {

private String lock = "lock";

private void method(){
synchronized (lock) {
try {
System.out.println(
"当前线程 : " + Thread.currentThread().getName() + "开始");
lock
= "change lock";
Thread.sleep(
2000);
System.out.println(
"当前线程 : " + Thread.currentThread().getName() + "结束");
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}

public static void main(String[] args) {

final ChangeLock changeLock = new ChangeLock();
Thread t1
= new Thread(new Runnable() {
@Override
public void run() {
changeLock.method();
}
},
"t1");
Thread t2
= new Thread(new Runnable() {
@Override
public void run() {
changeLock.method();
}
},
"t2");
t1.start();
try {
Thread.sleep(
100);
}
catch (InterruptedException e) {
e.printStackTrace();
}
t2.start();
}

}

 死锁问题:在设计程序时就应该避免双方相互持有对方的锁的情况,如下代码,会发生死锁问题,t1 进入lock1执行, t2 进入lock2执行。之后,t1去等待lock2对象解锁,t2去等待lock1对象解锁,这时谁也不能解锁,程序就会停在这里一直等待,这就是死锁问题。

package com.bjsxt.base.sync006;

/**
* 死锁问题,在设计程序时就应该避免双方相互持有对方的锁的情况
*
@author alienware
*
*/
public class DeadLock implements Runnable{

private String tag;
private static Object lock1 = new Object();
private static Object lock2 = new Object();

public void setTag(String tag){
this.tag = tag;
}

@Override
public void run() {
if(tag.equals("a")){
synchronized (lock1) {
try {
System.out.println(
"当前线程 : " + Thread.currentThread().getName() + " 进入lock1执行");
Thread.sleep(
2000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock2) {
System.out.println(
"当前线程 : " + Thread.currentThread().getName() + " 进入lock2执行");
}
}
}
if(tag.equals("b")){
synchronized (lock2) {
try {
System.out.println(
"当前线程 : " + Thread.currentThread().getName() + " 进入lock2执行");
Thread.sleep(
2000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock1) {
System.out.println(
"当前线程 : " + Thread.currentThread().getName() + " 进入lock1执行");
}
}
}
}

public static void main(String[] args) {

DeadLock d1
= new DeadLock();
d1.setTag(
"a");
DeadLock d2
= new DeadLock();
d2.setTag(
"b");

Thread t1
= new Thread(d1, "t1");
Thread t2
= new Thread(d2, "t2");

t1.start();
try {
Thread.sleep(
500);
}
catch (InterruptedException e) {
e.printStackTrace();
}
t2.start();
}



}

 

volatile:用volatile修饰的变量,线程在每次使用变量的时候,都会读取变量修改后的值。volatile很容易被误用,用来进行原子性操作。volatile关键字不具备synchronized关键字的原子性(同步)

JAVA高并发处理------多线程

AtomicInteger:一个提供原子操作的Integer的类。在Java语言中,++i和i++操作并不是线程安全的,在使用的时候,不可避免的会用到synchronized关键字。而AtomicInteger则通过一种线程安全的加减操作接口。注意:atomic类只保证本身方法的原子性,并不保证多次操作的原子性。比如说,我们使用AtomicInteger进行一次加十操作是具有原子性的,而同样是加十的操作,分成先加1,再加2,再加3,再加4这样四次操作,就不能保证原子性了。

脏读 :脏读就是指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。

在线程里调用变量变量必须用final修饰

wait释放锁,notify不释放锁。配合synchronized会有不实时的问题,这时有了下面的类。

CountDownLatch:一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。

主要方法

 public CountDownLatch(int count); 初始化计时器数量

 public void countDown();

 public void await() throws InterruptedException

构造方法参数指定了计数的次数

countDown方法,当前线程调用此方法,则计数减一

await方法,调用此方法会一直阻塞当前线程,直到计时器的值为0

ThreadLocal:ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。

JAVA高并发处理------多线程

多线程中的单例模式:

1.静态内部类--static inner class(饥汉模式)

package com.bjsxt.base.conn011;

public class Singletion {

private static class InnerSingletion {
private static Singletion single = new Singletion();
}

public static Singletion getInstance(){
return InnerSingletion.single;
}

}

2.双重确认--dubble check instance(懒汉模式)

package com.bjsxt.base.conn011;

public class DubbleSingleton {

private static DubbleSingleton ds;

public static DubbleSingleton getDs(){
if(ds == null){
try {
//模拟初始化对象的准备时间...
Thread.sleep(3000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (DubbleSingleton.class) {
if(ds == null){
ds
= new DubbleSingleton();
}
}
}
return ds;
}

public static void main(String[] args) {
Thread t1
= new Thread(new Runnable() {
@Override
public void run() {
System.out.println(DubbleSingleton.getDs().hashCode());
}
},
"t1");
Thread t2
= new Thread(new Runnable() {
@Override
public void run() {
System.out.println(DubbleSingleton.getDs().hashCode());
}
},
"t2");
Thread t3
= new Thread(new Runnable() {
@Override
public void run() {
System.out.println(DubbleSingleton.getDs().hashCode());
}
},
"t3");

t1.start();
t2.start();
t3.start();
}

}

 

同步类容器(不建议使用)

JAVA高并发处理------多线程

并发类容器

JAVA高并发处理------多线程

 JAVA高并发处理------多线程

 JAVA高并发处理------多线程

 

并发Queue:

JAVA高并发处理------多线程

 JAVA高并发处理------多线程

JAVA高并发处理------多线程

Futuer模式

JAVA高并发处理------多线程

JAVA高并发处理------多线程

Master-Worker模式

JAVA高并发处理------多线程