线程的安全问题:
多个线程共享一个全局变量或者静态变量,做写的时候可以是受到其他线程的干扰,导致数据问题,这就是线程的安全问题。在读取数据的时候不会产生线程安全问题。
经典的模拟抢票程序:
/**
* 两个线程同时抢100张火车票
*/
public class ThreadTraindemo01 implements Runnable {
private int count =100;
@Override
public void run() {
// 为了让程序一直抢票 模拟一个死循环
while(count>0){
try{
Thread.sleep(100);
}catch (Exception ex){
}
sale();
}
}
//卖票方法
public void sale(){
System.out.println(Thread.currentThread().getName()+":正在出售第"+(100-count+1)+"张火车票");
count--;
}
public static void main(String[] args) {
ThreadTraindemo01 threadTraindemo01 = new ThreadTraindemo01();
Thread thread1 = new Thread(threadTraindemo01,"窗口1正在卖票:");
Thread thread2 = new Thread(threadTraindemo01,"窗口2正在卖票:");
Thread thread3 = new Thread(threadTraindemo01,"窗口3正在卖票:");
thread1.start();
thread2.start();
thread3.start();
}
}
这样会出现重复售卖同一张票的现象。
使用线程安全解决问题:
/**
* 两个线程同时抢100张火车票
*/
public class ThreadTraindemo01 implements Runnable {
private int count =100;
@Override
public void run() {
// 为了让程序一直抢票 模拟一个死循环
synchronized (""){//解决线程安全问题。
while(count>0){
try{
Thread.sleep(100);
}catch (Exception ex){
}
sale();
}
}
}
//卖票方法
public void sale(){
System.out.println(Thread.currentThread().getName()+":正在出售第"+(100-count+1)+"张火车票");
count--;
}
public static void main(String[] args) {
ThreadTraindemo01 threadTraindemo01 = new ThreadTraindemo01();
Thread thread1 = new Thread(threadTraindemo01,"窗口1正在卖票:");
Thread thread2 = new Thread(threadTraindemo01,"窗口2正在卖票:");
Thread thread3 = new Thread(threadTraindemo01,"窗口3正在卖票:");
thread1.start();
thread2.start();
thread3.start();
}
}
线程共享同一个局部变量的时候不会产生线程安全问题。
因为局部变量每次都会被实例化。局部变量会变成线程私有的。
线程之间如何同步:
保证数据的原子性(数据不能受到其他数据干扰)。
解决办法:
1.synchronized –自动锁
2.lock锁—jdk1.5并发包里面的。–手动锁
使用同步代码块解决线程安全问题:
解决思路: 多个线程不能同时操作共享变量。
1.synchronized 解决线程安全问题:
前提:
1.线程的数量必须在两个线程以上,需要发生同步的地方。
2.多个线程的同步,必须使用同一把锁。
3.保证只用一个线程执行。
原理:1.又一个线程拿到锁,同时其他的线程已经拿到CPU的执行权,一直排队等待其他线程释放锁。
2.锁是咋代码执行完毕,或者程序抛出异常的时候锁被释放掉。
3.锁已经被释放掉,其他的线程开始获取锁进入到同步代码块中去。
4.锁资源的不是提高程序的效率,而是保证数据的原子性和完整性。
缺点:
效率很低(需要其他线程争夺资源锁,浪费资源。),会产生死锁的问题。
什么是线程同步:当多个线程共享一个资源的时候,不会收到其他线程的干扰。
一个任何类型的都可以
synchronized (""){
//解决线程安全问题的代码块
}
同步函数使用this锁:
在方法上加伤synchronized关键字;可以实现加锁。
public synchronized void sale(){
if(count>0){
System.out.println(Thread.currentThread().getName()+": 正在卖:"+(100-count+1)+" 张票");
count--;
}
}
同步函数使用的this锁
下面的代码可以证明同步函数使用的是this锁。
/**
* 下面的方法可以证明:同步函数使用的this这把锁
*/
public class ThreadTarinDemo03 implements Runnable {
private int count =100;
public boolean flag =true;
private Object obj =new Object();//当使用obj这把锁的时候会产生线程安全问题
@Override
public void run() {
if(flag){
try{
Thread.sleep(50);
while (count>0){
synchronized (this){//使用obj这把锁的时候会产生线程安全问题 。。使用this是不会产生线程安全的饿问题
if(count>0){
System.out.println(Thread.currentThread().getName()+"正在卖:"+(100-count+1)+"张票");
count--;
}
}
}
}catch (Exception ex){
}
}else {
while (count>0){
try{
sale();
}catch (Exception ex){
}
}
}
}
public synchronized void sale(){
if(count>0){
try{
Thread.sleep(50);
}catch (Exception ex){
}
System.out.println(Thread.currentThread().getName()+"正在卖:"+(100-count+1)+"张票");
count--;
}
}
public static void main(String[] args) {
ThreadTarinDemo03 threadTarinDemo03 = new ThreadTarinDemo03();
Thread thread1 = new Thread(threadTarinDemo03, "窗口一:");
Thread thread2 = new Thread(threadTarinDemo03, "窗口二:");
thread1.start();
try{
Thread.sleep(40);
threadTarinDemo03.flag =false;
}catch (Exception ex){
}
thread2.start();
}
}
面试题:
一个线程使用同步函数,另外一个线程使用同步代码块this可以实现同步吗?
肯定是可以实现同步的。因为同步函数使用的也是this锁。
一个线程使用同步函数,另外一个线程使用同步代码块如何实现同步。
在同步代码块中使用this锁。
静态代码块实现同步:
静态同步函数使用的不是this锁(因为静态的不存在this),要使用当前类的字节码文件(文件名.class)
package com.itmayiedu.day02;
/**
* 下面的代码证明static synchronized 这把锁使用的是this锁
* 使用的当前文件的class锁
*/
public class ThreadTrainDemo05 implements Runnable {
private static int count =100;
public boolean flag =true;
@Override
public void run() {
if(flag){
try{
Thread.sleep(50);
while (count>0){
synchronized (ThreadTrainDemo05.class){//使用this依然会产生线程安全问题。 但是使用当前文件的clss 不会产生线程安全问题
if(count>0){
System.out.println(Thread.currentThread().getName()+"正在卖第"+(100-count+1)+"张票");
count--;
}
}
}
} catch (Exception ex){
}
}else{
try{
Thread.sleep(50);
sale();
}catch (Exception ex){
}
}
}
public static synchronized void sale(){
if(count>0){
try{
Thread.sleep(40);
}catch (Exception ex){
}
System.out.println(Thread.currentThread().getName()+"正在卖第"+(100-count+1)+"张票");
count--;
}
}
public static void main(String[] args) {
ThreadTrainDemo05 threadTrainDemo05 = new ThreadTrainDemo05();
Thread thread1 = new Thread(threadTrainDemo05, "窗口1");
Thread thread2 = new Thread(threadTrainDemo05, "窗口2");
thread1.start();
try{
Thread.sleep(30);
threadTrainDemo05.flag= false;
}catch (Exception ex){
}
thread2.start();
}
}
面试题:
两个线程,一个线程使用同步函数,另外一个线程使用静态同步函数,可以实现连个线程的同步不?
不可以实现同步的。因为同步函数使用的是this锁,而静态同步函数使用的当前文件的字节码文件。(.class)
共享的全局变量是静态或者非静态的和同步函数或者静态同步函数没有关系的。
多线程死锁:
同步中嵌套同步,无法释放,一直等待