JUC笔记(How)
三、How
线程创建和使用
// 第四种:使用线程池来创建线程
@Test
public void test04(){
ExecutorService service = new ThreadPoolExecutor(
2,
Runtime.getRuntime().availableProcessors(),
2,
TimeUnit.SECONDS,
new LinkedBlockingDeque<>(3)
);
for (int i = 0; i < 10; i++) {
service.submit(()->{
System.out.println(Thread.currentThread().getName());
});
}
service.shutdown();
}
// 第三种:实现Callable接口来实现线程创建 : 可以有返回值、进行管理
@Test
public void test03() throws ExecutionException, InterruptedException {
class Test03 implements Callable<String> {
@Override
public String call() {
return "1";
}
}
Test03 test03 = new Test03();
FutureTask<String> ft=new FutureTask<>(test03);
//FutureTask实现了Runnable接口所以可以传入
Thread t=new Thread(ft);
t.start();
System.out.println(ft.get());
}
// 第二种:实现Runable接口来实现线程创建
@Test
public void test02(){
class Test02 implements Runnable{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("执行了run方法");
}
}
}
new Thread(new Test02()).start();
}
// 第一种:继承Thread类来实现线程创建
@Test
public void test01(){
class Test01 extends Thread{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("执行了run方法");
}
}
}
new Test01().start();
}
volatile关键字的使用
public class Demo01 {
private static volatile int num = 0;
// 三、禁止指令重排
/**
* 指令重排:程序运行时的样子不是你所理想型的样子,在不影响程序结果的前提下,指令执行的顺序可以进行调换。
*
* 初始化参数:a、b、x、y都为0
* 指令重排前的样子:
* 线程A:x = a;b = 1;
* 线程B:y = b;a = 2;
* 结果:x = 0;y = 0;
*
* 指令重排后的样子:
* 线程A:b = 1;x = a;
* 线程B:a = 2;y = b;
* 结果:x = 2;y = 1;
*
*/
// 使用AtomicInteger保持原子性
AtomicInteger atomicInteger = new AtomicInteger(0);
// 二、不保持原子性
@Test
public void test02(){
for (int i = 0; i < 10; i++) {
new Thread(()->num++).start();
}
System.out.println(num);
// 保持原子性
for (int i = 0; i < 10; i++) {
new Thread(()->atomicInteger.getAndIncrement()).start();
}
while (Thread.activeCount()>2){
Thread.yield();
}
System.out.println(atomicInteger.get());
}
// 一、保持可见性
/**
* 线程有单独的工作内存
*/
@Test
public void test01(){
new Thread(()-> {while(num == 0){}}).start();
num++;
System.out.println(num);
}
}
Lock锁的使用
// 生产者与消费者
public class Demo01 {
public static void main(String[] args){
ProductionAndConsumption pac = new ProductionAndConsumption();
for (int i = 0; i < 10; i++) {
new Thread(()->pac.getNumber()).start();
}
for (int i = 10; i < 20; i++) {
new Thread(()->pac.setNumber()).start();
}
}
}
class ProductionAndConsumption{
private int number = 0;
public Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
public void setNumber(){
lock.lock();
try{
while (number == 1){
try {
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.printf(Thread.currentThread().getName()+"\t生产\t库存: %s\n",++number);
condition.signalAll();
}catch(Exception e){
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void getNumber(){
lock.lock();
try{
while (number == 0){
try {
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.printf(Thread.currentThread().getName()+"\t消费\t\t库存: %s\n",--number);
condition.signalAll();
}catch(Exception e){
e.printStackTrace();
} finally {
lock.unlock();
}
}
// synchronized方式
// public synchronized void setNumber(){
// while (number == 1){
// try {
// wait();
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// }
// System.out.printf(Thread.currentThread().getName()+"\t生产\t库存: %s\n",++number);
// notifyAll();
// }
//
// public synchronized void getNumber(){
// while (number == 0){
// try {
// wait();
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// }
// System.out.printf(Thread.currentThread().getName()+"\t消费\t\t库存: %s\n",--number);
// notifyAll();
// }
}
ForkJoin的使用
public class SumTask extends RecursiveTask<Long> {
public static void main(String[] args){
// 创建随机数组成的数组:
long[] array = new long[400];
for (int i = 0; i < array.length; i++) {
array[i] = new Random().nextInt(1000);
}
// fork/join task:
ForkJoinPool fjp = new ForkJoinPool(4); // 最大并发数4
ForkJoinTask<Long> task = new SumTask(array, 0, array.length);
long startTime = System.currentTimeMillis();
Long result = fjp.invoke(task);
long endTime = System.currentTimeMillis();
System.out.println("Fork/join sum: " + result + " in " + (endTime - startTime) + " ms.");
}
static final int THRESHOLD = 100;
long[] array;
int start;
int end;
SumTask(long[] array, int start, int end) {
this.array = array;
this.start = start;
this.end = end;
}
@Override
protected Long compute() {
if (end - start <= THRESHOLD) {
// 如果任务足够小,直接计算:
long sum = 0;
for (int i = start; i < end; i++) {
sum += array[i];
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
System.out.println(String.format("compute %d~%d = %d", start, end, sum));
return sum;
}
// 任务太大,一分为二:
int middle = (end + start) / 2;
System.out.println(String.format("split %d~%d ==> %d~%d, %d~%d", start, end, start, middle, middle, end));
SumTask subtask1 = new SumTask(this.array, start, middle);
SumTask subtask2 = new SumTask(this.array, middle, end);
invokeAll(subtask1, subtask2);
Long subresult1 = subtask1.join();
Long subresult2 = subtask2.join();
Long result = subresult1 + subresult2;
System.out.println("result = " + subresult1 + " + " + subresult2 + " ==> " + result);
return result;
}
}