多线程安全

一.什么是线程安全

        当多个线程同时共享,同一个全局变量或静态变量,做写操作时,可能会发生数据冲突问题,也就是线程安全问题。但是做读操作时不会发生数据冲突问题。

public class ThreadDemo {
	
	public static void main(String[] args) {
		One one = new One();
		Thread t1 = new Thread(one);
		Thread t2 = new Thread(one);
		t1.start();			
		t2.start();
	}
}

class One implements Runnable {
	
	private int ticketCount = 10;
	
	public void run() {
		while(ticketCount > 0) {
			System.out.println(Thread.currentThread().getName() + "出售了车票:" + ticketCount);
			ticketCount--;
		}
	}
}

//控制台打印
Thread-1出售了车票:10
Thread-0出售了车票:10
Thread-1出售了车票:9
Thread-0出售了车票:8
Thread-1出售了车票:7
Thread-0出售了车票:6
Thread-1出售了车票:5
Thread-0出售了车票:4
Thread-1出售了车票:3
Thread-0出售了车票:2
Thread-1出售了车票:1

结论发现:多个线程共享同一个全局成员变量时,做写的操作可能会发生数据冲突问题。

二.线程安全解决方案

1.同步代码块

synchronized(对象) {
    //可能会发生线程冲突问题
}

对象如同锁,持有锁的线程可以在同步中执行,没持有锁的线程即使获取cpu的执行权,也进不去。

同步的前提

必须要有两个或者两个以上的线程

好处:解决了多线程的安全问题

弊端:多个线程需要判断锁,较为消耗资源,抢锁的资源

2.同步函数

在方法上修饰synchronized称为同步函数,同步函数使用this锁

public synchronized void sale() {
    //要执行的代码
}

3.静态同步函数

方法上加入static关键字,使用synchronized关键字修饰,静态同步代码块使用的锁是,该函数所属字节码文件对象

public synchronized static void sale() {
    //要执行的代码	
}

三.多线程死锁

同步中嵌套同步,导致无法释放锁

public class ThreadDemo {
	
	public static Object object1 = new Object();
	public static Object object2 = new Object();
	
	public static void main(String[] args) {
		One one = new One();
		Thread t1 = new Thread(one);
		t1.start();
		
		Two two = new Two();
		Thread t2 = new Thread(two);
		t2.start();
	}
}

class One implements Runnable {
	
	public void run() {
		while(true) {
			synchronized (ThreadDemo.object1) {
				System.out.println("oneObject1");
				
				synchronized (ThreadDemo.object2) {
					System.out.println("oneObject2");
				}
			}
		}
	}
}

class Two implements Runnable {
	
	public void run() {
		while(true) {
			synchronized (ThreadDemo.object2) {
				System.out.println("twoObject2");
				
				synchronized (ThreadDemo.object1) {
					System.out.println("twoObject1");
				}
			}
		}
	}
}

//控制台打印
oneObject2
oneObject1
oneObject2
oneObject1
oneObject2
oneObject1
oneObject2
oneObject1
twoObject2

线程one拿了object1线程two拿了object2,都在等待对方释放锁。双方都不释放锁,产生死锁。

四.多线程三大特性

1.原子性:即一个操作或者多个操作,要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行

2.可见性:当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看到修改的值

3.有序性:程序执行的顺序按照代码的先后顺序执行

五.java内存模型

java内存模型简称jmm,jmm决定一个线程对共享变量的写入时,能对一个线程可见。线程之间的共享变量存储在主内存中,每个线程都有一个私有的本地内存,本地内存中存储了该线程以读/写的副本。

每个线程都有自己的本地内存,当多个线程同时访问一个数据的时候,可能本地内存没有及时刷新到主内存,所以就会发生线程安全问题。

六.volatile关键字

volatile关键字的作用是变量在多个线程之间可见。强制每次读取都会去主内存中取值。volatile不具备原子性。

volatile与synchronized的区别

1.volatile轻量级,只能修饰变量。synchronized重量级还弄修饰方法。

2.volatile只能保证数据的可见性,不能用来同步,因为多个线程并发访问volatile修饰的变量不会阻塞。

synchronized不仅保证可见性,而且还保证原子性,因为,只有获取了锁的线程才能进入临界区,从而保存临界区中的所有语句都全部执行,多个线程争抢synchronized锁对象时,会出现阻塞。

线程安全性包括1.可见性  2.原子性

volatile并不能保证线程安全性,而synchronized则可实现线程的安全性。

七.atomiclnteger原子类

Atomiclnteger是一个提供原子操作的integer类,通过线程安全的方式操作加减。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值