深入理解Java多线程(三)JUC基础篇

本文详细探讨了Java并发编程中的JUC组件,包括volatile的特性、原子操作类如AtomicInteger和LongAdder的使用,以及ReentrantLock、CountDownLatch、CyclicBarrier、Phaser、Semaphore和Exchanger的实战应用。通过实例代码分析,帮助读者深入理解这些并发工具类的原理和性能差异。

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

这篇文章主要侧重讲JUC的多数类的使用,文章里贴了很多练习的代码,可以通过代码更加深刻的了解这些类的功能。

这篇文章主要总结了volatile、原子类、ReentrantLock、CountDownLatch、CyclicBarrier、Phaser、Semphore、Exchanger的使用,然后进行了一些对比。

个人博客:https://www.elltor.com/archives/110.html
欢迎访问,相互学习,共同进步👋

volatile

volatile使用
/*
 * 演示volatile的作用
 * 若running不使用volatile修饰则在主线程(main)修改running=false线程不会停下,而是继续运行
 * 
 * 结论:通过volatile修饰running可以让线程使用running时获得最新值
 * 
 * volatile的作用:
 * 1)使共享变量在线程间可见,通过JMM内存协议,CPU缓存一致性协议使缓存失效,直接读取内存中的数据
 * 2)阻止指令重排序
 */
public class T_VolatileTest {
   
   

    static class Task implements Runnable{
   
   
        /*volatile*/ boolean running  = true;
        @Override
        public void run() {
   
   
            System.out.println("thread start");
            while (running){
   
   

            }
            System.out.println("thread end");
        }
    }

    public static void main(String[] args) {
   
   
        Task t = new Task();
        new Thread(t).start();

        try {
   
   
            Thread.sleep(1000); //1s
        } catch (InterruptedException e) {
   
   
            e.printStackTrace();
        }
        t.running = false;
        System.out.println("set running=false");
    }
}
volatile并不是锁
/*
 * volatile并不能代替volatile,多并发环境下的m方法如果不同步执行,结果是错的。
 * 在对m方法同步后,结果输出正确。
 * 
 * 结论:
 * 1)volatile不能够做锁
 * 2)它仅具有使多线程间共享变量可见,但不具有同步的功能
 */
public class T_VolatileNotSync {
   
   
	volatile int count = 0;
	/*synchronized*/ void m() {
   
   
		for(int i=0; i<1000; i++) count++;
	}

	public static void main(String[] args) {
   
   
		T_VolatileNotSync t = new T_VolatileNotSync();
		
		List<Thread> threads = new ArrayList<Thread>();
		
		for(int i=0; i<10; i++) {
   
   
			threads.add(new Thread(t::m, "thread-"+i));
		}

		// 启动线程
        for (Thread th : threads) {
   
   
            th.start();
            
        }
		
        // 阻塞到所有线程执行完毕
		threads.forEach((o)->{
   
   
			try {
   
   
				o.join();
			} catch (InterruptedException e) {
   
   
				e.printStackTrace();
			}
		});
		
        // 输出结果
		System.out.println(t.count);
	}
}
volatile只能保证引用本身可见,内部数据不能保证
/*
 * 在引用上t加volatile,只能保证引用(类、数组实例)本身可见,不能保证内部可见
 */
public class T_VolatileReference {
   
   
    static volatile Task t = new Task();
    
    static class Task implements Runnable{
   
   
        boolean running = true;

        @Override
        public void run() {
   
   
            System.out.println("run start");
            while(running) {
   
   
            }
            System.out.println("run end!");
        }
    }

    public static void main(String[] args) {
   
   
        Thread thread = new Thread(t);

        thread.start();

        try {
   
   
            Thread.sleep(1000);
        } catch (InterruptedException e) {
   
   
            e.printStackTrace();
        }

        t.running = false;
    }
}

原子操作类

原子操作类使java.util.atomic包下的类,这些类为操作提供了原子性,使用时不用进行额外的同步,这些操作仅限于对原子类对象进行操作,如果多个原子类多对象进行操作还是需要额外的同步。

AutomicInteger使用

在Counter类中AutomicInteger并没有使用volatile修饰,并且run中的integer.incrementAndGet()没有进行同步,最终这些操作并没有在多线程环境下出错。

// Atomic 操作是原子操作
public class TestAtomic {
   
   

    static class Counter implements Runnable{
   
   
        AtomicInteger integer = new AtomicInteger(0);

        @Override
        public void run() {
   
   
            for (int i = 0; i < 10000; i++) {
   
   
                integer.incrementAndGet();
            }
        }
    }

    public static void main(String[] args) {
   
   
        List<Thread> threadList = new ArrayList<>(10);
        Counter c = new Counter();

        // 10个线程对Counter进行类型,每个线程执行run会累加10000此,最终结果为10 0000
        for (int i = 0; i < 10; i++) {
   
   
            threadList.add(new Thread(c));
        }


        for (Thread thread : threadList) {
   
   
            thread.start();
        }

        // 阻塞到所有线程执行完毕
        for (Thread thread : threadList) {
   
   
            try {
   
   
                thread.join();
            } catch (InterruptedException e) {
   
   
                e.printStackTrace();
            }
        }

        // result
        System.out.println(c.integer.get());
    }
}

使用原子类实现CAS操作。

// 使用原子类的CAS
// 使两个线程协作输出两个字符串 str1=123456 str2=ABCDEF, 要求结果输出为:1A2B3C4D5E6F
public class TestAtomic2 {
   
   

    public static void main(String[] args) {
   
   
        String str1 = "123456";
        String str2 = "ABCDEF";

        // cas 锁
        AtomicInteger mutex = new AtomicInteger(0);

        // CAS操作,threa1在0输出,thread2在1时输出

        // thread 1
        new Thread(() -> {
   
   
            for (int i = 0; i < str1.length(); i++) {
   
   
                // 与期望的值不符进行空循环
		while (mutex.get()!=0) {
   
   

                }
                System.out.print(str1.charAt(i));
                mutex.set(1);

            }

        
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值