java多线程之三大特性

本文深入探讨Java多线程的三大核心特性:原子性、可见性和有序性,并通过实例演示如何确保线程安全,包括使用AtomicInteger解决x++操作的原子性问题,以及volatile关键字确保变量的可见性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

java多线程之三大特性

1.原子性

  1. 和数据库中事务的原子性差不多。即一个操作或者多个操作,要么全部执行并前执行的过程不会被任何因素打断,要么就都不执行。在Java中,对基本数据类型的变量的读取和赋值都是原子性操作,即这些操作是不可被中断的,要么执行,要么不执行。
    2.诸如x++等操作不是原子性
import java.util.concurrent.atomic.AtomicInteger;
/*
 * 测试多线程的原子性
 */
public class ThreadAtomicDemo {
	public static  int x =0;
	
	public static class AtomicThread extends Thread{
		@Override
		public void run() {
			while(true) {
				x++;//x++   x--   ++x  --x都不是原子性(原子性指的是操作不能分割)
				System.out.println(this.getName()+"::"+x);
				
				try {
					sleep(200);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}
	
	
	public static void main(String[] args) {
		Thread t1 =new AtomicThread();
		t1.setName("A");
		Thread t2 =new AtomicThread();
		t2.setName("B");
		Thread t3 =new AtomicThread();
		t3.setName("C");
		
		t1.start();
		t2.start();
		t3.start();
	}

}

在这里插入图片描述
观察上述结果,我们可以发现三个线程输出的值,和我们预想的值不一样。输出应该是从1一直递加。那么出现这种情况的原因是x++符合原子性。x++在需要进行两步操作:1.x=x;2.x++。这样就会造成线程不安全。我们可以通过使用原子操作类,例如AtomicInteger,AtomicBoolean …来解决这一问题。。。。。

import java.util.concurrent.atomic.AtomicInteger;
/*
 * 测试多线程的原子性
 */
public class ThreadAtomicDemo {
	//public static  int x =0;
	public static final AtomicInteger x = new AtomicInteger(0);//原子性
	public static class AtomicThread extends Thread{
		@Override
		public void run() {
			while(true) {
				//x++;//x++   x--   ++x  --x都不是原子性(原子性指的是操作不能分割)
				//System.out.println(this.getName()+"::"+x);
				System.out.println(this.getName()+"::"+x.incrementAndGet());//自增
				try {
					sleep(200);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}
	
	
	public static void main(String[] args) {
		Thread t1 =new AtomicThread();
		t1.setName("A");
		Thread t2 =new AtomicThread();
		t2.setName("B");
		Thread t3 =new AtomicThread();
		t3.setName("C");
		
		t1.start();
		t2.start();
		t3.start();
	}

}

在这里插入图片描述
在这里插入图片描述

这里原子性的实现原理,不是加锁,而是CAS(Compare And Swap)算法的实现。。。。

CAS我们后面再仔细分析。。。

2.可见性

现代计算机中,由于CPU直接从主内存中读取数据的效率不高,所以都会对应的CPU高速缓存,先将主内存中的数据读取到缓存中,线程修改数据之后首先更新到缓存,之后才会更新到主内存。如果此时还没有将数据更新到主内存其他的线程此时来读取就是修改之前的数据。

/*
 * 测试多线程的可见性
 */
public class VisableThreadDemo {
	public static  boolean f =false;//这里必须加可见性,否则f变成true,但是A中看不到
	
	public static class A extends Thread{
		@Override
		public void run() {
			while(true) {
				if(f) {
					System.out.println(getName()+"运行:"+f);
					break;
				}
			}
		}
	}
	
	public static class B extends Thread{
		@Override
		public void run() {
			try {
				sleep(1000);
			} catch (InterruptedException e) {
				
				e.printStackTrace();
			}
			f =true;
			System.out.println(getName()+"运行:"+f);
		}
	}
	
	public static void main(String[] args) {
		Thread t1 = new A();
		t1.setName("A");
		Thread t2 = new B();
		t2.setName("B");
		
		t1.start();
		t2.start();
	}

}

在这里插入图片描述
通过上面的程序,我们发现线程A没有被运行,因为B线程在缓存区将f改为true。主内存中的f没有改变,所以A线程没有运行。
在这里插入图片描述

/*
 * 测试多线程的可见性
 */
public class VisableThreadDemo {
	public static volatile boolean f =false;//这里必须加可见性,否则f变成true,但是A中看不到
	
	public static class A extends Thread{
		@Override
		public void run() {
			while(true) {
				if(f) {
					System.out.println(getName()+"运行:"+f);
					break;
				}
			}
		}
	}
	
	public static class B extends Thread{
		@Override
		public void run() {
			try {
				sleep(1000);
			} catch (InterruptedException e) {
				
				e.printStackTrace();
			}
			f =true;
			System.out.println(getName()+"运行:"+f);
		}
	}
	
	public static void main(String[] args) {
		Thread t1 = new A();
		t1.setName("A");
		Thread t2 = new B();
		t2.setName("B");
		
		t1.start();
		t2.start();
	}

}

在这里插入图片描述

3.有序性

有序性,即程序执行的顺序按照代码的先后顺序执行。在Java内存模型中,允许编译器和处理器对指令进行重排序,但是重排序过程不会影响到单线程程序的执行,却会影响到多线程并发执行的正确性。

/**
 * 单例模型,关于线程的有序性测试
 * @author Administrator
 *
 */
public class OrderThreadDemo {

	private  static volatile OrderThreadDemo instance = null;
	
	private OrderThreadDemo() {}
	
	
	public static OrderThreadDemo getInstance() {
		/**
		 * 两个线程进入方法
		 *   if   instance == null 
		 *   准备创建对象  instance = new OrderThreadDemo();
		 *   可能分为三个流程:
		 *     1. 开辟内存空间
		 *     2. 初始化对象
		 *     3. 引用和对象绑定
		 *     
		 *     另外一种方式:
		 *      1. 开辟内存空间
		 *      2. 引用和对象绑定   instance--->对象,instance不是null
		 *      3. 初始化对象(未完成)
		 */
		
		 if(instance==null) {//判断OrderThreadDemo对象是否存在
			 instance = new OrderThreadDemo();
		 }
		 
		 return instance;//多线程中可能会抛异常
	}

}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值