Java-JUC入门

通关JUC:Java并发工具包从入门到精通 | 深度源码解析​ 想要征服Java并发编程的挑战?本文带你系统通关JUC(Java Util Concurrent)!我们从基础概念与核心组件(如线程池、锁工具、并发集合)讲起,循序渐进直达高级应用。​不止于会用,更深入剖析其精妙源码(如ThreadPoolExecutor、AQS、ConcurrentHashMap)​,揭示设计思想与性能奥秘。​助你从入门到精通,构建扎实的Java并发知识体系,写出高效稳定的高并发代码。理论+源码,通关JUC必备! 阅读详情

目录:

  1. 内存可见性
  2. CAS&i++ 的原子性问题
  3. ConcurrentHashMap 锁分段 
  4. CopyOrWriteArrayList 写入复制 (并发迭代 遍历优先使用)
  5. CountDownLatch 闭锁 应用场景()
  6. 用于解决多线程问题  同步代码块   同步方法  同步锁
  7. 生产者消费者   1.虚假唤醒  需要放到循环中
  8. 线程按序交替 lock condition
  9. 读写锁  readWriteLock
  10. 线程8锁
  11. 线程池

1.内存可见性

volatile 关键字:当多个线程进行操作共享数据时,可以保证内存中的数据可见。相较于 synchronized 是一种较为轻量级的同步策略。
 注意:
 1. volatile 不具备“互斥性”
 2. volatile 不能保证变量的“原子性”


public class TestVolatile {

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

        while (true) {
            if (td.isFlag()) {
                System.out.println("------------------");
                break;
            }
        }

    }

}

class ThreadDemo implements Runnable {

    private volatile boolean flag = false;

    @Override
    public void run() {

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

        flag = true;

        System.out.println("flag=" + isFlag());

    }

    public boolean isFlag() {
        return flag;
    }

    public void setFlag(boolean flag) {
        this.flag = flag;
    }

}

2.CAS &i++ 的原子性问题

    



import java.util.concurrent.atomic.AtomicInteger;

/**
 * 一、i++ 的原子性问题:i++ 的操作实际上分为三个步骤“读-改-写”
 * int i = 10;
 * i = i++; //10
 * <p>
 * int temp = i;
 * i = i + 1;
 * i = temp;
 * <p>
 * 二、原子变量:在 java.util.concurrent.atomic 包下提供了一些原子变量。
 * 1. volatile 保证内存可见性
 * 2. CAS(Compare-And-Swap) 算法保证数据变量的原子性
 * CAS 算法是硬件对于并发操作的支持
 * CAS 包含了三个操作数:
 * ①内存值  V
 * ②预估值  A
 * ③更新值  B
 * 当且仅当 V == A 时, V = B; 否则,不会执行任何操作。
 */
public class TestAtomicDemo {

    public static void main(String[] args) {
        AtomicDemo ad = new AtomicDemo();

        for (int i = 0; i < 10; i++) {
            new Thread(ad).start();
        }
    }

}

class AtomicDemo implements Runnable {

//	private volatile int serialNumber = 0;

    private AtomicInteger serialNumber = new AtomicInteger(0);

    @Override
    public void run() {

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

        System.out.println(getSerialNumber());
    }

    public int getSerialNumber() {
        return serialNumber.getAndIncrement();
    }


}

模拟CAS 手写简单算法 

/**
 * 模拟 CAS 算法
 */
public class TestCompareAndSwap {

    public static void main(String[] args) {
        final CompareAndSwap cas = new CompareAndSwap();

        for (int i = 0; i < 10; i++) {
            new Thread(new Runnable() {

                @Override
                public void run() {
                    int expectedValue = cas.get();
                    boolean b = cas.compareAndSet(expectedValue, (int) (Math.random() * 101));
                    System.out.println(b);
                }
            }).start();
        }

    }

}

class CompareAndSwap {
    private int value;

    //获取内存值
    public synchronized int get() {
        return value;
    }

    //比较
    public synchronized int compareAndSwap(int expectedValue, int newValue) {
        int oldValue = value;

        if (oldValue == expectedValue) {
            this.value = newValue;
        }

        return oldValue;
    }

    //设置
    public synchronized boolean compareAndSet(int expectedValue, int newValue) {
        return expectedValue == compareAndSwap(expectedValue, newValue);
    }
}

3.ConcurrentHashMap 分段锁

在JDK1.7中ConcurrentHashMap采用了数组+Segment+分段锁的方式实现。

  • Segment(分段锁):ConcurrentHashMap中的分段锁称为Segment,它即类似于HashMap的结构,即内部拥有一个Entry数组,数组中的每个元素又是一个链表,同时又是一个ReentrantLock(Segment继承了ReentrantLock)。
  • 内部结构:ConcurrentHashMap使用分段锁技术,将数据分成一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其他段的数据也能被其他线程访问,能够实现真正的并发访问。

 4.CopyOrWriteArrayList 写入复制

注意:添加操作多时,效率低,因为每次添加时都会进行复制,开销非常的大。并发迭代操作多时可以选择。

import java.util.Iterator;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * CopyOnWriteArrayList/CopyOnWriteArraySet : “写入并复制”
 * 
 */
public class TestCopyOnWriteArrayList {

    public static void main(String[] args) {
        HelloThread ht = new HelloThread();

        for (int i = 0; i < 10; i++) {
            new Thread(ht).start();
        }
    }

}

class HelloThread implements Runnable {

//	private static List<String> list = Collections.synchronizedList(new ArrayList<String>());

    private static CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();

    static {
        list.add("AA");
        list.add("BB");
        list.add("CC");
    }

    @Override
    public void run() {

        Iterator<String> it = list.iterator();

        while (it.hasNext()) {
            System.out.println(it.next());

            list.add("AA");
        }

    }

}

5.CountDownLatch 闭锁

CountDownLatch :闭锁,在完成某些运算是,只有其他所有线程的运算全部完成,当前运算才继续执行

import java.util.concurrent.CountDownLatch;

public class TestCountDownLatch {

    public static void main(String[] args) {
        final CountDownLatch latch = new CountDownLatch(50);
        LatchDemo ld = new LatchDemo(latch);

        long start = System.currentTimeMillis();

        for (int i = 0; i < 50; i++) {
            new Thread(ld).start();
        }

        try {
            latch.await();
        } catch (InterruptedException e) {
        }

        long end = System.currentTimeMillis();

        System.out.println("耗费时间为:" + (end - start));
    }

}

class LatchDemo implements Runnable {

    private CountDownLatch latch;

    public LatchDemo(CountDownLatch latch) {
        this.latch = latch;
    }

    @Override
    public void run() {

        try {
            for (int i = 0; i < 50000; i++) {
                if (i % 2 == 0) {
                    System.out.println(i);
                }
            }
        } finally {
            latch.countDown();
        }

    }

}

7.生产者消费者


/*
 * 生产者和消费者案例
 */
public class TestProductorAndConsumer {

    public static void main(String[] args) {
        Clerk clerk = new Clerk();

        Productor pro = new Productor(clerk);
        Consumer cus = new Consumer(clerk);

        new Thread(pro, "生产者 A").start();
        new Thread(cus, "消费者 B").start();

        new Thread(pro, "生产者 C").start();
        new Thread(cus, "消费者 D").start();
    }

}

/*//店员
class Clerk{
	private int product = 0;
	
	//进货
	public synchronized void get(){//循环次数:0
		while(product >= 1){//为了避免虚假唤醒问题,应该总是使用在循环中
			System.out.println("产品已满!");
			
			try {
				this.wait();
			} catch (InterruptedException e) {
			}
			
		}
		
		System.out.println(Thread.currentThread().getName() + " : " + ++product);
		this.notifyAll();
	}
	
	//卖货
	public synchronized void sale(){//product = 0; 循环次数:0
		while(product <= 0){
			System.out.println("缺货!");
			
			try {
				this.wait();
			} catch (InterruptedException e) {
			}
		}
		
		System.out.println(Thread.currentThread().getName() + " : " + --product);
		this.notifyAll();
	}
}

//生产者
class Productor implements Runnable{
	private Clerk clerk;

	public Productor(Clerk clerk) {
		this.clerk = clerk;
	}

	@Override
	public void run() {
		for (int i = 0; i < 20; i++) {
			try {
				Thread.sleep(200);
			} catch (InterruptedException e) {
			}
			
			clerk.get();
		}
	}
}

//消费者
class Consumer implements Runnable{
	private Clerk clerk;

	public Consumer(Clerk clerk) {
		this.clerk = clerk;
	}

	@Override
	public void run() {
		for (int i = 0; i < 20; i++) {
			clerk.sale();
		}
	}
}*/
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 生产者消费者案例:
 */
public class TestProductorAndConsumerForLock {

	public static void main(String[] args) {
		Clerk clerk = new Clerk();

		Productor pro = new Productor(clerk);
		Consumer con = new Consumer(clerk);

		new Thread(pro, "生产者 A").start();
		new Thread(con, "消费者 B").start();

//		 new Thread(pro, "生产者 C").start();
//		 new Thread(con, "消费者 D").start();
	}

}

class Clerk {
	private int product = 0;

	private Lock lock = new ReentrantLock();
	private Condition condition = lock.newCondition();

	// 进货
	public void get() {
		lock.lock();

		try {
			if (product >= 1) { // 为了避免虚假唤醒,应该总是使用在循环中。
				System.out.println("产品已满!");

				try {
					condition.await();
				} catch (InterruptedException e) {
				}

			}
			System.out.println(Thread.currentThread().getName() + " : " + ++product);

			condition.signalAll();
		} finally {
			lock.unlock();
		}

	}

	// 卖货
	public void sale() {
		lock.lock();

		try {
			if (product <= 0) {
				System.out.println("缺货!");

				try {
					condition.await();
				} catch (InterruptedException e) {
				}
			}

			System.out.println(Thread.currentThread().getName() + " : " + --product);

			condition.signalAll();

		} finally {
			lock.unlock();
		}
	}
}

// 生产者
class Productor implements Runnable {

	private Clerk clerk;

	public Productor(Clerk clerk) {
		this.clerk = clerk;
	}

	@Override
	public void run() {
		for (int i = 0; i < 20; i++) {
			try {
				Thread.sleep(200);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}

			clerk.get();
		}
	}
}

// 消费者
class Consumer implements Runnable {

	private Clerk clerk;

	public Consumer(Clerk clerk) {
		this.clerk = clerk;
	}

	@Override
	public void run() {
		for (int i = 0; i < 20; i++) {
			clerk.sale();
		}
	}

}

8.线程按序交替


import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 编写一个程序,开启 3 个线程,这三个线程的 ID 分别为 A、B、C,每个线程将自己的 ID 在屏幕上打印 10 遍,要求输出的结果必须按顺序显示。
 * 如:ABCABCABC…… 依次递归
 */
public class TestABCAlternate {

	public static void main(String[] args) {
		AlternateDemo ad = new AlternateDemo();

		new Thread(new Runnable() {
			@Override
			public void run() {

				for (int i = 1; i <= 20; i++) {
					ad.loopA(i);
				}

			}
		}, "A").start();

		new Thread(new Runnable() {
			@Override
			public void run() {

				for (int i = 1; i <= 20; i++) {
					ad.loopB(i);
				}

			}
		}, "B").start();

		new Thread(new Runnable() {
			@Override
			public void run() {

				for (int i = 1; i <= 20; i++) {
					ad.loopC(i);

					System.out.println("-----------------------------------");
				}

			}
		}, "C").start();
	}

}

class AlternateDemo {

	private int number = 1; //当前正在执行线程的标记

	private Lock lock = new ReentrantLock();
	private Condition condition1 = lock.newCondition();
	private Condition condition2 = lock.newCondition();
	private Condition condition3 = lock.newCondition();

	/**
	 * @param totalLoop : 循环第几轮
	 */
	public void loopA(int totalLoop) {
		lock.lock();

		try {
			//1. 判断
			if (number != 1) {
				condition1.await();
			}

			//2. 打印
			for (int i = 1; i <= 1; i++) {
				System.out.println(Thread.currentThread().getName() + "\t" + i + "\t" + totalLoop);
			}

			//3. 唤醒
			number = 2;
			condition2.signal();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			lock.unlock();
		}
	}

	public void loopB(int totalLoop) {
		lock.lock();

		try {
			//1. 判断
			if (number != 2) {
				condition2.await();
			}

			//2. 打印
			for (int i = 1; i <= 1; i++) {
				System.out.println(Thread.currentThread().getName() + "\t" + i + "\t" + totalLoop);
			}

			//3. 唤醒
			number = 3;
			condition3.signal();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			lock.unlock();
		}
	}

	public void loopC(int totalLoop) {
		lock.lock();

		try {
			//1. 判断
			if (number != 3) {
				condition3.await();
			}

			//2. 打印
			for (int i = 1; i <= 1; i++) {
				System.out.println(Thread.currentThread().getName() + "\t" + i + "\t" + totalLoop);
			}

			//3. 唤醒
			number = 1;
			condition1.signal();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			lock.unlock();
		}
	}

}

9.读写锁  readWriteLock

import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * 1. ReadWriteLock : 读写锁
 * <p>
 * 写写/读写 需要“互斥”
 * 读读 不需要互斥
 */
public class TestReadWriteLock {

    public static void main(String[] args) {
        ReadWriteLockDemo rw = new ReadWriteLockDemo();

        new Thread(new Runnable() {

            @Override
            public void run() {
                rw.set((int) (Math.random() * 101));
            }
        }, "Write:").start();


        for (int i = 0; i < 100; i++) {
            new Thread(new Runnable() {

                @Override
                public void run() {
                    rw.get();
                }
            }).start();
        }
    }

}

class ReadWriteLockDemo {

    private int number = 0;

    private ReadWriteLock lock = new ReentrantReadWriteLock();

    //读
    public void get() {
        lock.readLock().lock(); //上锁

        try {
            System.out.println(Thread.currentThread().getName() + " : " + number);
        } finally {
            lock.readLock().unlock(); //释放锁
        }
    }

    //写
    public void set(int number) {
        lock.writeLock().lock();

        try {
            System.out.println(Thread.currentThread().getName());
            this.number = number;
        } finally {
            lock.writeLock().unlock();
        }
    }
}

10.线程8锁

/**
 * 题目:判断打印的 "one" or "two" ?
 * <p>
 * 1. 两个普通同步方法,两个线程,标准打印, 打印? //one  two
 * 2. 新增 Thread.sleep() 给 getOne() ,打印? //one  two
 * 3. 新增普通方法 getThree() , 打印? //three  one   two
 * 4. 两个普通同步方法,两个 Number 对象,打印?  //two  one
 * 5. 修改 getOne() 为静态同步方法,打印?  //two   one
 * 6. 修改两个方法均为静态同步方法,一个 Number 对象?  //one   two
 * 7. 一个静态同步方法,一个非静态同步方法,两个 Number 对象?  //two  one
 * 8. 两个静态同步方法,两个 Number 对象?   //one  two
 * <p>
 * 线程八锁的关键:
 * ①非静态方法的锁默认为  this,  静态方法的锁为 对应的 Class 实例
 * ②某一个时刻内,只能有一个线程持有锁,无论几个方法。
 */
public class TestThread8Monitor {

    public static void main(String[] args) {
        Number number = new Number();
        Number number2 = new Number();

        new Thread(new Runnable() {
            @Override
            public void run() {
                number.getOne();
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
//				number.getTwo();
                number2.getTwo();
            }
        }).start();
		
		/*new Thread(new Runnable() {
			@Override
			public void run() {
				number.getThree();
			}
		}).start();*/

    }

}

class Number {

    public static synchronized void getOne() {//Number.class
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
        }

        System.out.println("one");
    }

    public synchronized void getTwo() {//this
        System.out.println("two");
    }

    public void getThree() {
        System.out.println("three");
    }

}

11、线程池

      11.1线程池创建

   

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
 * 一、创建执行线程的方式三:实现 Callable 接口。 相较于实现 Runnable 接口的方式,方法可以有返回值,并且可以抛出异常。
 * <p>
 * 二、执行 Callable 方式,需要 FutureTask 实现类的支持,用于接收运算结果。  FutureTask 是  Future 接口的实现类
 */
public class TestCallable {

    public static void main(String[] args) {
        ThreadDemo td = new ThreadDemo();

        //1.执行 Callable 方式,需要 FutureTask 实现类的支持,用于接收运算结果。
        FutureTask<Integer> result = new FutureTask<>(td);

        new Thread(result).start();

        //2.接收线程运算后的结果
        try {
            Integer sum = result.get();  //FutureTask 可用于 闭锁
            System.out.println(sum);
            System.out.println("------------------------------------");
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
    }

}

class ThreadDemo implements Callable<Integer> {

    @Override
    public Integer call() throws Exception {
        int sum = 0;

        for (int i = 0; i <= 100000; i++) {
            sum += i;
        }

        return sum;
    }

}

/*class ThreadDemo implements Runnable{

	@Override
	public void run() {
	}

}*/

11.2线程池介绍

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

/**
 * 一、线程池:提供了一个线程队列,队列中保存着所有等待状态的线程。避免了创建与销毁额外开销,提高了响应的速度。
 * <p>
 * 二、线程池的体系结构:
 * java.util.concurrent.Executor : 负责线程的使用与调度的根接口
 * |--**ExecutorService 子接口: 线程池的主要接口
 * |--ThreadPoolExecutor 线程池的实现类
 * |--ScheduledExecutorService 子接口:负责线程的调度
 * |--ScheduledThreadPoolExecutor :继承 ThreadPoolExecutor, 实现 ScheduledExecutorService
 * <p>
 * 三、工具类 : Executors
 * ExecutorService newFixedThreadPool() : 创建固定大小的线程池
 * ExecutorService newCachedThreadPool() : 缓存线程池,线程池的数量不固定,可以根据需求自动的更改数量。
 * ExecutorService newSingleThreadExecutor() : 创建单个线程池。线程池中只有一个线程
 * <p>
 * ScheduledExecutorService newScheduledThreadPool() : 创建固定大小的线程,可以延迟或定时的执行任务。
 */
public class TestThreadPool {

    public static void main(String[] args) throws Exception {
        //1. 创建线程池
        ExecutorService pool = Executors.newFixedThreadPool(5);

        List<Future<Integer>> list = new ArrayList<>();

        for (int i = 0; i < 10; i++) {
            Future<Integer> future = pool.submit(new Callable<Integer>() {

                @Override
                public Integer call() throws Exception {
                    int sum = 0;

                    for (int i = 0; i <= 100; i++) {
                        sum += i;
                    }

                    return sum;
                }

            });

            list.add(future);
        }

        pool.shutdown();

        for (Future<Integer> future : list) {
            System.out.println(future.get());
        }
		
		
		
		/*ThreadPoolDemo tpd = new ThreadPoolDemo();
		
		//2. 为线程池中的线程分配任务
		for (int i = 0; i < 10; i++) {
			pool.submit(tpd);
		}
		
		//3. 关闭线程池
		pool.shutdown();*/
    }

//	new Thread(tpd).start();
//	new Thread(tpd).start();

}

class ThreadPoolDemo implements Runnable {

    private int i = 0;

    @Override
    public void run() {
        while (i <= 100) {
            System.out.println(Thread.currentThread().getName() + " : " + i++);
        }
    }

}
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * 一、线程池:提供了一个线程队列,队列中保存着所有等待状态的线程。避免了创建与销毁额外开销,提高了响应的速度。
 * 
 * 二、线程池的体系结构:
 * 	java.util.concurrent.Executor : 负责线程的使用与调度的根接口
 * 		|--**ExecutorService 子接口: 线程池的主要接口
 * 			|--ThreadPoolExecutor 线程池的实现类
 * 			|--ScheduledExecutorService 子接口:负责线程的调度
 * 				|--ScheduledThreadPoolExecutor :继承 ThreadPoolExecutor, 实现 ScheduledExecutorService
 * 
 * 三、工具类 : Executors 
 * ExecutorService newFixedThreadPool() : 创建固定大小的线程池
 * ExecutorService newCachedThreadPool() : 缓存线程池,线程池的数量不固定,可以根据需求自动的更改数量。
 * ExecutorService newSingleThreadExecutor() : 创建单个线程池。线程池中只有一个线程
 * 
 * ScheduledExecutorService newScheduledThreadPool() : 创建固定大小的线程,可以延迟或定时的执行任务。
 */
public class TestScheduledThreadPool {

	public static void main(String[] args) throws Exception {
		ScheduledExecutorService pool = Executors.newScheduledThreadPool(5);
		
		for (int i = 0; i < 5; i++) {
			Future<Integer> result = pool.schedule(new Callable<Integer>(){

				@Override
				public Integer call() throws Exception {
					int num = new Random().nextInt(100);//生成随机数
					System.out.println(Thread.currentThread().getName() + " : " + num);
					return num;
				}
				
			}, 1, TimeUnit.SECONDS);
			
			System.out.println(result.get());
		}
		
		pool.shutdown();
	}
	
}

13.ForkJoin框架

import org.junit.Test;

import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveTask;
import java.util.stream.LongStream;


public class TestForkJoinPool {

    public static void main(String[] args) {
        Instant start = Instant.now();

        ForkJoinPool pool = new ForkJoinPool();

        ForkJoinTask<Long> task = new ForkJoinSumCalculate(0L, 50000000000L);

        Long sum = pool.invoke(task);

        System.out.println(sum);

        Instant end = Instant.now();

        System.out.println("耗费时间为:" + Duration.between(start, end).toMillis());//166-1996-10590
    }

    @Test
    public void test1() {
        Instant start = Instant.now();

        long sum = 0L;

        for (long i = 0L; i <= 50000000000L; i++) {
            sum += i;
        }

        System.out.println(sum);

        Instant end = Instant.now();

        System.out.println("耗费时间为:" + Duration.between(start, end).toMillis());//35-3142-15704
    }

    //java8 新特性
    @Test
    public void test2() {
        Instant start = Instant.now();

        Long sum = LongStream.rangeClosed(0L, 50000000000L)
                .parallel()
                .reduce(0L, Long::sum);

        System.out.println(sum);

        Instant end = Instant.now();

        System.out.println("耗费时间为:" + Duration.between(start, end).toMillis());//1536-8118
    }

}

class ForkJoinSumCalculate extends RecursiveTask<Long> {

    /**
     *
     */
    private static final long serialVersionUID = -259195479995561737L;

    private long start;
    private long end;

    private static final long THURSHOLD = 10000L;  //临界值

    public ForkJoinSumCalculate(long start, long end) {
        this.start = start;
        this.end = end;
    }

    @Override
    protected Long compute() {
        long length = end - start;

        if (length <= THURSHOLD) {
            long sum = 0L;

            for (long i = start; i <= end; i++) {
                sum += i;
            }

            return sum;
        } else {
            long middle = (start + end) / 2;

            ForkJoinSumCalculate left = new ForkJoinSumCalculate(start, middle);
            left.fork(); //进行拆分,同时压入线程队列

            ForkJoinSumCalculate right = new ForkJoinSumCalculate(middle + 1, end);
            right.fork(); //

            return left.join() + right.join();
        }
    }

}

Godot4 TileMap分层绘制全攻略:解决角色、树木遮挡混乱,打造正确视觉层级 本文详细介绍了Godot4 TileMap分层绘制技术,通过图层管理和Y-Sort功能解决2D游戏中角色与物体的遮挡问题。从基础图层设置到高级优化策略,帮助开发者打造符合自然视觉规律的场景层次,提升游戏沉浸感。特别针对TileMap和TileSet的使用提供了实用技巧和代码示例。 阅读详情

相关推荐

【芯片验证随心记】1.SystemVerilog中,rand和randc的区别?如何用constraint实现randc?

在SystemVerilog里,randc 的“不重复循环”特性是用一个 周期性排列器(permutation engine) 实现的,而这个引擎在 LRM 里并没有公开。我们只能在 “用户空间” 用 rand + constraint 去模仿它的行为。每次随机化只取 queue.pop_front(),用完再洗。在4次随机化内,y会依次出现0,1,2,3各一次(顺序随机)每次随机化,x可能是0-3中的任意值,可能连续多次相同。每次随机化时,在未使用的值里随机挑一个;第5次随机化时,重新生成新的排列周期。

qq_43172512的博客 342

Java面试题:解释Java内存模型中的内存可见性,解释Java中的线程池(ThreadPool)的工作原理,解释Java中的CountDownLatch和CyclicBarrier的区别

本文通过三道新的面试题,深入探讨了Java内存模型、多线程和并发相关的核心知识点。理解这些概念不仅有助于面试准备,也是成为一名优秀的Java开发者所必需的。希望读者能够通过本文的解析,对Java底层的复杂机制有更清晰的认识,并在实际工作中能够灵活运用这些知识,以编写出高效、稳定的Java程序。

杰哥在此的专栏 559

蓝牙开发那些事之ceva controller代码解读

对比ceva的经典蓝牙和ble的controller在软件上的差异点

袁赟的博客 1090

Java笔记-JUC基础

JUC

虽然但是 704

从零开始理解异构算力调度:全国一体化算力算网平台实战解析

本文深入解析了异构算力调度技术在全国一体化算力算网平台中的实战应用。通过资源抽象层设计、动态感知引擎和跨云调度算法,实现AI训练任务的高效资源分配,显著提升计算效率并降低成本。特别针对GPU等异构算力的智能调度方案,为多云协同环境下的AI开发提供实用指南。

weixin_28730927的博客 334

ESP8266连接阿里云(STM32)

一、概述 之前通过串口调试助手+ESP8266已经连接上阿里云了 ESP8266连接阿里云(串口调试助手) 这次我们使用STM32+ESP8266来接入阿里云,其实本质上就是STM32和ESP8266进行串口通信,相当于使用STM32代替之前使用的串口调试助手来发送AT指令。只是发送的字符串数据可能有些细节需要注意一下。 二、保存连接的AT指令 定义几个字符串数据保存需要发送的AT指令 //注意: //末尾记得加\r\n //字符...

xyx0610的博客 4万+

多线程并发之CountDownLatch(闭锁)使用详解

【1】CountDownLatch是什么 CountDownLatch,英文翻译为倒计时锁存器。是一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。 闭锁可以延迟线程的进度直到其到达终止状态,闭锁可以用来确保某些活动直到其他活动都完成才继续执行: 确保某个计算在其需要的所有资源都被初始化之后才继续执行; 确保某个服务在其依赖的所有其他服务都已经启动之后才...

小小默:进无止境 2万+

ADS2019学习笔记:三、SPICE model导入

以BZX84-C33 SPICE model为例,学习如何在ADS2019中导入SPICE model。

qq_42945911的博客 6494

java--JUC快速入门(彻底搞懂JUC)

线程池:一种线程使用模式。线程过多会带来调度开销,进而影响缓存局部性和整体性能。而线程池维护着多个线程,等待着监督管理者分配可并发执行的任务。这避免了在处理短时间任务时创建与销毁线程的代价。线程池不仅能够保证内核的充分利用,还能防止过分调度。

qq_53808097的博客 4161

OpenClaw 在 Docker 容器中的部署实战——零配置启动

本文介绍了OpenClaw在Docker容器中的快速部署方法,对比了本地部署与容器化部署的优势。通过官方镜像和Docker Compose两种方式,5分钟即可完成部署,并详细讲解了配置管理方案(挂载配置文件和环境变量)。文章还提供了飞书集成配置方法,以及生产环境下的日志管理、资源限制、健康检查等优化建议。最后包含常见问题排查指南,帮助开发者快速实现OpenClaw的容器化部署。

刘一说的IT专栏 905

YOLOv10改进 | 代码逐行解析(三) | YOLO中的Mosaic增强详解(新手入门必读系列)

本文给大家带来的是YOLOv10中的Mosaic增强代码的详解,可能有部分人对于这一部分比较陌生,有的读者可能知道Mosaic增强但是不知道其工作原理,具体来说Mosaic增强就是指我们的数据集中的图片在输入给模型之前的一个处理过程(我们的图片并不是直接就输入给模型了,大家的训练结果中的结果检测图片大家可以看到数据集中多个图片会组合在一起这就是简单的Mosaic增强),下面我就来讲解一下其在YOLOv10中工作原理和代码定义,下面图片为一个Mosaic增强后的图片。​。

Snu77的博客 2077

【java 高并发编程之JUC】2w字带你JUC从入门到精通

wait()是让获得对象锁的线程实现等待,会自动释放当前线程占有的对象锁。每个对象(Object)都拥有对象锁,既然要释放当前线程占有的对象锁并让其进入 WAITING 状态,自然是要操作对应的对象(Object)而非当前的线程(Thread为什么sleep()方法定义在Thread中?因为sleep()是让当前线程暂停执行,不涉及到对象类,也不需要获得对象锁。java JUC 中 Object里wait()、notify() 实现原理及实战讲解。

LoveSummer 6万+

案例:无人船测量点位数据+ArcGIS 10.6软件生成三维水下地形的两种方法

通常情况下,采用无人船进行水下地形测量,得到的是离散的,具有点号、日期、时间、东坐标(E)、北坐标(N)、水面高程、水下高程和水深等信息的点位数据,该数据一般由航带点位数据加水岸线组成,如下图所示: 原始点位数据格式如下: 下面讲解在ArcGIS软件中生成三维水下地形的两种常用方法。 一、构建不规则三角网(Tin) 1、创建Tin 生成的Tin: 2、Tin转栅格 Tin to Raster: 三维展示: 二、空间插值 栅格插值常用的方法有:克里...

智慧空间实验室 6752

Java入门(基础,常见API,JVM,JUC并发编程)

Java初学者软件安装与idea快捷键-优快云博客 Java基本概念(新手入门)_阿伟java资料-优快云博客JavaAPI-优快云博客JVM入门-优快云博客JUC并发编程-优快云博客

2301_76556912的博客 1220

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

java-JUC入门

文章目录Java多线程之读写锁——ReadWriteLock应用说明演示Java多线程——8锁问题描述案例线程八锁的关键:Java等待唤醒机制JUC版普通解决线程通信方式jdk1.5后解决线程通信方式线程控制练习Java创建线程的方式——实现Callable接口说明使用Callable接口创建线程与实现Runnable的区别代码演示:接收返回值和捕获异常Java多线程开发之volatile关键字说...

Ken的博客 853

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

【JUC】Java并发编程入门:JUC核心API解析

Java并发编程基础摘要 JUC(java.util.concurrent)是Java 5引入的并发工具包,提供了线程管理、同步任务和并发处理的核心API。本文介绍了JUC基础概念和使用方法: 进程与线程:进程是独立运行的程序,线程是执行单元。Java默认多线程运行。 Thread与Runnable: Thread类实现线程,Runnable定义任务逻辑 示例展示了两种线程创建方式及join()等待机制 synchronized同步: 通过方法或代码块保证线程安全 代码示例演示了如何用synchronize

白晨的博客 1219

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

JUC快速入门(彻底搞懂JUC)

java JUC

抽象的螺旋 342

从入门到实战:Java JUC 并发工具包完全指南

JUC 是 java.util.concurrent 包的简称,从 Java 5 开始引入,专门用于解决并发编程中的线程同步、线程池、锁机制、并发集合等问题,是 Java 处理高并发场景的核心工具包。它弥补了传统 synchronized`关键字、Thread 类的局限性,提供了更高效、更灵活的并发编程方案。

2201_75355172的博客 2132

Java 并发 JUC 入门与进阶完全指南

在单核时代,写好一个顺序执行的程序就够了;但在多核 CPU 与高并发服务的今天,并发编程是每个 Java 工程师绕不开的必修课。Java 从 JDK 1.5 开始,把一整套经过千锤百炼的并发工具收进了 包——也就是大家口中的 JUC(Java Util Concurrent)[1]。这篇教程从"为什么需要并发"讲起,带你走完 JUC 的入门篇、进阶篇,最后看看 JDK 21 之后虚拟线程与结构化并发开启的新范式。先用一个生活类比:一个人做家务,洗衣服 30 分钟、做饭 20 分钟、吃饭 15 分钟、看电视

如果足够勇敢 应该扛起问题往前走 直到因果成熟自动脱落 人对问题的解决方式 不是试图找到答案 而是背负到可以解决的那一天 397

万字长文入门Java的JUC

    前言 一、内存可见性与volatile关键字 二、原子变量和CAS算法 三、同步容器类和ConcurrentHashMap 四、ContDownLatch闭锁 五、创建线程的第三种方式 六、Lock同步锁 七、Condition线程通信 八、读写锁 九、线程八锁 十、线程池 十一、线程调度 十二、ForkJoin分支合并框架 前言 JUC的全称是java.util.concurrent...

DanDan的博客 675

java并发编程 JUC-基础篇 快速入门

程序有指令与数据组成,指令要运行,数据要读写,就必须指令加载到CPU。数据加载到内容,指令运行需要用到磁盘。当一个程序被运行时,从磁盘加载这个程序的代码至内存,这时开启了一个进程。

制定持续可量化的目标,不断坚持。 1430

高级Java编程-----JUC基础入门(一)

目录什么是JUC 本系列 什么是JUC

LOL_toulan的博客 584

java开发juc并发之AQS入门

AQS 全称:AbstractQueuedSynchronizer,它是​​java培训​​学习中JUC并发工具包中 ReentrantLock 、CountDownLatch、CyclicBarrier等这些类的底层实现。此篇我们主要通过ReentrantLock的使用来大体了解AQS底层代码设计原理,不对源码详细赘述。只要对整体的设计方向有清晰了解,再去追踪源码便不是什么难事。阅读本篇之前,需要大家对ReentrantLock 的API有一定了解。 ReentrantLock的lock、await方法

m0_58371965的博客 148

深入 JUC 入门核心:Java 多线程创建与运行机制全解析(Java 实习生必修课)

在操作系统中,线程(Thread)是CPU 调度的基本单位,而进程(Process)是资源分配的基本单位。一个进程可包含多个线程,它们共享进程的内存空间(堆、方法区),但拥有独立的栈(Stack)。📌关键特性轻量级:创建/切换线程比进程开销小;共享内存:线程间通信高效,但也带来数据竞争(Race Condition)风险;并发执行:多核 CPU 可真正并行;单核 CPU 通过时间片轮转实现“伪并行”。“创建线程”看似简单,实则蕴含操作系统、JVM、Java API 三层知识。线程的本质。

吾为热爱计科,致力于知识分享的践行者,此博客是我在这条道路上留下的足迹。 1021
上一篇: enterprise architect绘画ER图
下一篇: JVM从入门到精通(持续更新中)
HelloWorld_AA
博客等级 码龄9年 18粉丝 96原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值