栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

JUC并发编程

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

JUC并发编程

1.Lambda表达式

Lambda表达式是jdk1.8出现的编码方式,主要作用是让代码更加简洁,也可以提高代码的内聚,减少代码中不必要的实现类。
如何写一个java实现类

interface InterFaceDemo{
    int add();

    default int demo(int x ,int y){
        return x+y;
    }
}

public class LambdaExpress {
    public static void main(String[] args) {
        InterFaceDemo demo =  ()->{
            System.out.println();
            return 1;
        };
    }
}

函数式接口:java8新特性的一种,用于标识接口。一般把这样的接口用于链式编程中。

接口中的静态方法:与普通类中的静态方法没有区别,调用方式:接口.方法名直接使用

多线程编程 1.概念

1.多线程编程方法:在高内聚低耦合的前提下,线程操作资源类。

2.多线程编程流程:判断——>干活——>通知

3.多线程编程中需要注意的问题:虚假唤醒,判断标志变量只能使用while不能使用if。
原因:if只会做一次判断,而while会循环判断直到变量值变为期望值。

4.标志位移,一般用于做为判断条件。

资源类

资源类=实例变量+实例方法

public class Ticket {
    private  int number = 30;

    Lock lock = new ReentrantLock();
    public void sale(){
        lock.lock();
        try {
            if ( number > 0){
                System.out.println(Thread.currentThread().getName()+"t卖出第:"+(number--)
                +"t 还剩下:"+number
                );
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}
操作

一般是指线程使用资源类中的方法打到某种目的。

线程

通常情况下采用匿名内部类的方式定义线程

//普通版本
new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 40; i++) {
                    ticket.sale();
                }
            }
        },"A").start();
//Lambda 表达式版本
new Thread(()->{for (int i = 0; i < 40; i++) ticket.sale();
        },"B").start();
JDK1.8之后消费者和生产者写法的区别

主要是添加了lock与condition来帮助加锁与唤醒线程。

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


//    旧版
//    public synchronized void increase()throws InterruptedException{
//        if (number!=0){
//            this.wait();
//        }
//        number++;
//        System.out.println(Thread.currentThread().getName()+"t"+number);
//        this.notifyAll();
//    }
    public  void increase()throws InterruptedException{
            while (number!=0){
                condition.await();
            }
            number++;
            System.out.println(Thread.currentThread().getName()+"t"+number);
            condition.signalAll();
        }
使用新方法的原因

能够实现线程间的精准通知。

package JUC;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
// A 五次 B 十次 C 15次的顺序 十轮
class ShareResource{
    // 标志位
    private int number = 1;
    private Lock lock = new ReentrantLock();
    private Condition conditionA = lock.newCondition();
    private Condition conditionB = lock.newCondition();
    private Condition conditionC= lock.newCondition();

    public void print(int count){
        lock.lock();
        try {
            //判断
            if (count == 5) {
                while (number != 1) {
                    conditionA.await();
                }
                conditionAwait(5,conditionB,2);
            }
            if (count == 10) {
                while (number != 2) {
                    conditionB.await();
                }
                conditionAwait(10,conditionC,3);
            }
            if (count == 15) {
                while (number != 3) {
                    conditionC.await();
                }
                conditionAwait(15,conditionA,1);
            }
            } catch(Exception e){
                e.printStackTrace();
            } finally{
                lock.unlock();
            }
        }


    public void conditionAwait(int count,Condition condition,int value) throws InterruptedException {
        for (int i = 0; i < count; i++) {
            System.out.println(Thread.currentThread().getName() + " /t" + "现在是第" + i + "次打印");
        }
        number = value;
        condition.signal();
    }
}
public class ThreadOrderAccess {
    public static void main(String[] args) {
        ShareResource shareResource = new ShareResource();

        new Thread(()->{
            for (int i = 0; i <10 ; i++) {
                shareResource.print(5);
            }
        },"A").start();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                shareResource.print(10);
            }
        },"B").start();
        new Thread(()->{
            for (int i = 0; i < 15; i++) {
                shareResource.print(15);
            }

        },"C").start();

    }
}
多线程中创建多线程的几种方式
    继承Thread类实现Runnabble接口实现Callable接口
Runnable与Callable有什么区别
    Callable有返回值Runnable没有Callable抛出异常,Runnable没有方法命 Callable叫call Runnable叫run
    通过Callable创建线程的一般方法:
package ThreadLocal;

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


class MyThread implements Callable{

	@Override
	public Integer call() throws Exception {
		System.out.println("come in here");
		return 1111;
	}
}

public class CallableDemo {
	public static void main(String[] args) throws ExecutionException, InterruptedException {
		FutureTask futureTask = new FutureTask(new MyThread());
		new Thread(futureTask,"A").start();
		System.out.println(futureTask.get());
	}

}

使用FutureTask执行任务
需要注意的几点,在使用FutureTask时如果立即get会阻塞只到线程得到结果才能继续向下执行,如果不需要立刻得到结果可以在get钱添加其他业务逻辑。示例:

package ThreadLocal;

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


class MyThread implements Callable{

	@Override
	public Integer call() throws Exception {
		System.out.println("come in here");
		return 1111;
	}
}

public class CallableDemo {
	public static void main(String[] args) throws ExecutionException, InterruptedException {
		FutureTask futureTask = new FutureTask(new MyThread());
		new Thread(futureTask,"A").start();
        
		System.out.println(futureTask.get());
	}

}

8锁

现在有一个手机对象,拥有两个功能都被synchronize方法修饰:1.短信发送,2.发送邮件

    标准访问,请问先打印邮件还是短信? 先打印邮件后打印短信

    邮件方法暂停4秒钟,请问先打印邮件还是短信?

    新增普通方法hello( ),先打印邮件还是hello?

    两部手机,请问先打印邮件还是短信?

    两个静态同步方法,一部手机,先打印邮件还是短信

    两个静态同步方法,两部手机,请问先打印邮件还是短信

    一个普通同步方法,一个静态同步方法,一部手机,请问先打印邮件还是短信?

    一个普通同步方法,一个静态同步方法,两部手机,请问先打印邮件还是短信?

8锁问题的回答:

Synchronize实现同步的基础:java中的对象都可以作为锁
具体表现为以下三种形式
1.对于普通同步方法:锁是当前对象
2.对于静态同步方法:锁是当前对象类的Class对象
3.对于同步方法块:锁是synchronize括号中配置的对象

一个对象(资源类)中如果有多个方法被synchronize修饰,只要其中一个被加锁的方法被使用,那么其他线程如果也要使用被加锁的方法只能等待。

普通方法(不加synchronize的方法)不受synchronize影响,即便当前对象被锁也能正常访问。

使用同一个类创建出来的对象虽然功能相同,但他们是两个不同的锁。

静态同步方法锁的是类本身,而不是当前对象。

所有非静态同步方法的锁对象都是对象本身:this

同步方法、同步方法块

线程访问普通方法锁的是实例对象自身。调用带有synchronize的方法需要获得锁对象,当没有获得锁对象时,线程会因为没有对于的锁对象而进入等待状态。因为锁对象是对象本身,如果创建新的实例对象(new一个对象)还是能够通过新的实例对象调用同步方法的。

非线程安全的类 List

主要表现:多线程环境下回发生ConcurrentModificationException
解决方法:
1.使用synchronize或lock进行同步操作
2.使用数组中的Vector
3.使用CopyOnWriteArrayList

CopyonWriteArrayList

添加元素的过程:将原容器的数据复制出来用一个新的容器装载,当向新容器中添加完成之后,再将原容器的引用指向新的容器
好处:因为读和写是在不同的容器中,所以能够保证在元素添加完成前不管怎么读数据都是一致的。
源码:

public boolean add(E e) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            Object[] elements = getArray();
            int len = elements.length;
            Object[] newElements = Arrays.copyOf(elements, len + 1);
            newElements[len] = e;
            setArray(newElements);
            return true;
        } finally {
            lock.unlock();
        }
    }
Map

解决Map线程不安全的方法:ConcurrentHashMap

Set

多线程下发生:ConcurrentModificationException
解决方法:CopyOnWriteArraySet

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/735785.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号