我们实际上去公司写线程的代码时,不能让我们的资源类去继承Thread或者实现Runnable接口,我们应该将资源类完全隔离开来,它里面就只有属性和方法。
//基本的买票例子
//真正的多线程开发,公司中的开发一定要降低耦合性,线程就是一个单独的资源类,没有任何的附属操作
//里面包含有1.属性 2.方法
public class SaleTicketDemo01 {
public static void main(String[] args) {
//并发:多个线程操作同一个资源类
Ticket ticket = new Ticket();
new Thread(()->{
for (int i = 0; i < 40; i++) {
ticket.sale();
}
},"A").start();
new Thread(()->{
for (int i = 0; i < 40; i++) {
ticket.sale();
}
},"B").start();
new Thread(()->{
for (int i = 0; i < 40; i++) {
ticket.sale();
}
},"C").start();
}
}
//资源类 OOP编程
class Ticket{
//属性,方法
private int number = 50;
//买票的方式
//synchronize本质就是一个队列
public synchronized void sale(){
if (number>0){
System.out.println(Thread.currentThread().getName()+"卖出了第"+(number--)+"张票,剩余"+number);
}
}
}

我们通过运用Lock的实现类来加锁
我们先来看一下ReentrantLock的构造器,它默认是返回一个非公平锁,这让的目录就是提高运行效率,比如说

公平锁:十分公平,可以先来后到
非公平锁:十分不公平,可以插队
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
//基本的买票例子
//真正的多线程开发,公司中的开发一定要降低耦合性,线程就是一个单独的资源类,没有任何的附属操作
//里面包含有1.属性 2.方法
public class SaleTicketDemo02 {
public static void main(String[] args) {
//并发:多个线程操作同一个资源类
Ticket2 ticket = new Ticket2();
new Thread(()->{
for (int i = 0; i < 40; i++) ticket.sale();
},"A").start();
new Thread(()->{
for (int i = 0; i < 40; i++) ticket.sale();
},"B").start();
new Thread(()->{
for (int i = 0; i < 40; i++) ticket.sale();
},"C").start();
}
}
//资源类 OOP编程
//1.new ReentrantLock
//2.加锁
//3.解锁
class Ticket2{
//属性,方法
private int number = 50;
Lock lock = new ReentrantLock();
//买票的方式
//synchronize本质就是一个队列
public void sale(){
lock.lock();//加锁
try{
if (number>0){
System.out.println(Thread.currentThread().getName()+"卖出了第"+(number--)+"张票,剩余"+number);
}
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
}

public class A {
public static void main(String[] args) {
Data data = new Data();
new Thread(()->{
for (int i = 0; i < 20; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"A").start();
new Thread(()->{
for (int i = 0; i < 20; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"B").start();
}
}
//等待,业务,通知
class Data{//数字 资源类
private int number = 0;
//+1
public synchronized void increment() throws InterruptedException {
if (number!=0){
this.wait();
}
number++;
System.out.println(Thread.currentThread().getName()+"加操作");
this.notifyAll();
}
//-1
public synchronized void decrement() throws InterruptedException {
if (number==0){
this.wait();
}
number--;
System.out.println(Thread.currentThread().getName()+"减操作");
this.notifyAll();
}
}

这里一定要用while,if只会判断一次,等待应该总是出现在循环中。不能说判断条件中途改变了就立刻不wait了
public class A {
public static void main(String[] args) {
Data data = new Data();
new Thread(()->{
for (int i = 0; i < 20; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"A").start();
new Thread(()->{
for (int i = 0; i < 20; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"B").start();
new Thread(()->{
for (int i = 0; i < 20; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"C").start();
new Thread(()->{
for (int i = 0; i < 20; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"D").start();
}
}
//等待,业务,通知
class Data{//数字 资源类
private int number = 0;
//+1
public synchronized void increment() throws InterruptedException {
while (number!=0){
this.wait();
}
number++;
System.out.println(Thread.currentThread().getName()+"加操作");
this.notifyAll();
}
//-1
public synchronized void decrement() throws InterruptedException {
while (number==0){
this.wait();
}
number--;
System.out.println(Thread.currentThread().getName()+"减操作");
this.notifyAll();
}
}

condition就是替代同步监视,替换掉我们之前用的Synchronized的版本
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class B {
public static void main(String[] args) {
Data2 data = new Data2();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"A").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"B").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"C").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"D").start();
}
}
//等待,业务,通知
class Data2{//数字 资源类
private int number = 0;
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
//+1
public void increment() throws InterruptedException {
lock.lock();
try {
while (number!=0){
condition.await();
}
number++;
condition.signalAll();
System.out.println(Thread.currentThread().getName()+"加操作");
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
//-1
public void decrement() throws InterruptedException {
lock.lock();
try {
while (number==0){
condition.await();
}
number--;
condition.signalAll();
System.out.println(Thread.currentThread().getName()+"减操作");
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
condition除了可以替换wait和notifyall更重要的一点功能使它强于sychronized就是它可以精准的通知和唤醒线程,notify()只能随机唤醒一个线程,是由线程调度器随机分配的,notifyall它默认唤醒所有线程。
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
//A执行完调用B,B执行完调用C,C执行完调用A
public class C {
public static void main(String[] args) {
Data3 data3 = new Data3();
new Thread(()->{
for (int i = 0; i < 10; i++) {
data3.print1();
}
},"A").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
data3.print2();
}
},"B").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
data3.print3();
}
},"C").start();
}
}
class Data3{//资源类
private int number = 1;//1A 2B 3C
private Lock lock = new ReentrantLock();
//创建三个不同的监视器,通过监视器来判断我们到底应该唤醒的是哪个人
Condition condition1 = lock.newCondition();
Condition condition2 = lock.newCondition();
Condition condition3 = lock.newCondition();
public void print1(){
lock.lock();
try {
//业务,判断是否等待的过程,判断是否执行,通知
while (number!=1){
//等待
condition1.await();
}
System.out.println(Thread.currentThread().getName()+"在执行");
number = 2;
condition2.signal();
} catch (Exception e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
public void print2(){
lock.lock();
try {
//业务,判断是否等待的过程,判断是否执行,通知
while (number!=2){
condition2.await();
}
System.out.println(Thread.currentThread().getName()+"在执行");
number = 3;
condition3.signal();
} catch (Exception e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
public void print3(){
lock.lock();
try {
//业务,判断是否等待的过程,判断是否执行,通知
while (number!=3){
condition3.await();
}
System.out.println(Thread.currentThread().getName()+"在执行");
number = 1;
condition1.signal();
} catch (Exception e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
这种精准调用的应用:生产线:下单--》支付--》交易--》物流
锁的是谁?
import java.util.concurrent.TimeUnit;
/**
* 标准情况下,是先打印发短信还是先打印打电话呢?
* 那我们要是在这个sendSms中去加一个sleep呢,结果又会怎样呢?
* 其实这里无论怎么变化都是先会打印发短信,再打印打电话的。
*/
public class Test1 {
public static void main(String[] args) {
Phone phone = new Phone();
new Thread(()->{
phone.sendSms();
},"A").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone.call();
},"B").start();
}
}
class Phone{
//synchronized其实锁的是方法的调用者,这也就不难解释上面我们只创建了一个Phone对象
public synchronized void sendSms() {
System.out.println("发短信");
}
public synchronized void call() {
System.out.println("打电话");
}
}

import java.util.concurrent.TimeUnit;
public class Test2 {
public static void main(String[] args) {
Phone2 phone = new Phone2();
new Thread(()->{
phone.sendSms();
},"A").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone.hello();
},"B").start();
}
}
class Phone2{
public synchronized void sendSms() {
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public synchronized void call() {
System.out.println("打电话");
}
//这里没有锁!不是同步方法,不受锁的影响
public void hello(){
System.out.println("hello");
}
}

import java.util.concurrent.TimeUnit;
public class Test3 {
public static void main(String[] args) {
Phone3 phone1 = new Phone3();
Phone3 phone2 = new Phone3();
new Thread(()->{
phone1.sendSms();
},"A").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone2.call();
},"B").start();
}
}
class Phone3{
//static 静态方法
// 类一加载了就有了,加了static的同步方法锁的就是方法调用者的class
// 当然我们也知道无论有多少个对象都只有一个class
public static synchronized void sendSms() {
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public static synchronized void call() {
System.out.println("打电话");
}
}

import java.util.concurrent.TimeUnit;
/**
* 锁的东西都不一样
*/
public class Test4 {
public static void main(String[] args) {
Phone4 phone = new Phone4();
new Thread(()->{
phone.sendSms();
},"A").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone.call();
},"B").start();
}
}
class Phone4 {
//静态同步方法
public static synchronized void sendSms() {
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
//普通同步方法
public synchronized void call() {
System.out.println("打电话");
}
}

首先Vector是线程安全的,ArrayList是线程不安全的


import com.sun.xml.internal.ws.api.model.wsdl.WSDLOutput;
import java.lang.reflect.Array;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
// java.util.ConcurrentModificationException 并发修改异常
public class ListTest {
public static void main(String[] args) {
/**
* 原本:List<String> list = new ArrayList<>();
* 解决方法:
* 1.将ArrayList换成Vector List<String> list = new Vector<>();
* 2.采用集合的顶级工具类来进行一个转化 List<String> list = Collections.synchronizedList(new ArrayList<>());
* 3.采用JUC包下的 CopyOnWrite:写入时复制(提高计算机程序设计领域的一种优化策略)List<String> list = new CopyOnWriteArrayList<>();
* 为什么了要有这个东西呢,因为在多线程写入的时候可能出现写入覆盖的问题,在写入的时候呢我们先copy一份再写入再放回去。
* 读写分离 (写入的时候复制一份来写)
* CopyOnWriteArrayList 比 Vector 牛逼在那里,只要有synchronized方法效率就比较低,Vector用的是synchornized
* CopyOnWriteArrayList 用的是Lock
*/
List<String> list = new CopyOnWriteArrayList<>();
for (int i = 0; i < 10; i++) {
new Thread(()->{
list.add(UUID.randomUUID().toString().substring(0,5));
System.out.println(list);
},String.valueOf(i)).start();
}
}
}

import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CopyOnWriteArraySet;
public class SetTest {
public static void main(String[] args) {
Set<String> set1 = new HashSet<>();
//方法一
Set<String> set2 = Collections.synchronizedSet(new HashSet<>());
//方法二
Set<String> set3 = new CopyOnWriteArraySet<>();
for (int i = 0; i < 100; i++) {
new Thread(()->{
set.add(UUID.randomUUID().toString().substring(0,5));
},String.valueOf(i)).start();
}
}
}
扩展:HashSet的底层就是一个HashMap,就是用了它的这个key,key是不重复的。

HashSet.add(),其实就是将你要存的数据当作HashMap的key存进去罢了。key不会重复,set不允许有重复的值。

PRESENT其实就是一个固定的不变的值。

HashMap构造方法中:


import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
public class MapTest {
public static void main(String[] args) {
//map是这样用的吗? 不是,工作中不用这样的HashMap
// 默认等价于什么? Map<String, Object> map = new HashMap<>(16,0.75);
Map<String, Object> map = new HashMap<>();
//方法一:
Map<Object, Object> objectObjectMap = Collections.synchronizedMap(new HashMap<>());
//方法二:
Map<String,Object> map1 = new ConcurrentHashMap<>();
//加载因子,初始容量
for (int i = 0; i < 30; i++) {
new Thread(()->{
map.put(Thread.currentThread().getName(), UUID.randomUUID().toString().substring(0,5));
},String.valueOf(i)).start();
}
}
}
原文:https://www.cnblogs.com/yaoyaoo/p/14375247.html