JUC是java.util.concurrent
在并发编程中使用的工具包
进程(Process ) 是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体。是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。程序是指令、数据及其组织形式的描述,进程是程序的实体。
线程( thread ) 是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。v
( 1 ) sleep是Thread的静态方法,wait是 Object的方法,任何对象实例都能调用。
( 2 ) sleep不会释放锁,它也不需要占用锁。wait 会释放锁,但调用它的前提是当前线程占有锁(即代码要在synchronized中)。
(3)它们都可以被interrupted方法中断。
并发:同一时刻多个线程在访问同一个资源,多个线程对一个点·
例子︰春运抢票 电商秒杀 .…
并行:多项工作一起执行,之后再汇总
例子︰泡方便面,电水壶烧水,一边撕调料倒入桶中;
管程 是一种同步机制,保证同一个时间,只有一个线程访问被保护数据或者代码
jvm同步基于进入和退出,使用管程对象实现的
用户线程∶自定义线程(主线程结束了,用户线程还在运行, jvm存活)
守护线程:比如垃圾回收(没有用户线程了,都是守护线程,jvm结束)
public class Main01 {
public static void main(String[] args) {
Thread aa=new Thread(()->{
System.out.println(Thread.currentThread().getName()+"::"+Thread.currentThread().isDaemon());
while (true){}
},"aa");
//aa设置成守护线程
//aa.setDaemon(true);
aa.start();
System.out.println(Thread.currentThread().getName()+"over");
}
}
虽然main主方法结束了 但自定义线程aa还在死循环中 那么程序还在运行中( jvm存活)
将aa设置成守护线程 主线程结束 没有用户线程 那么程序停止(jvm结束)
synchronized是Java中的关键字,是一种同步锁。它修饰的对象有以下几种:
3个售票员 卖出30张票
class Ticket{
private int num =30;
synchronized void sale(){
if(num>0){
System.out.println(Thread.currentThread().getName()+"卖出,"+"剩余:"+(--num ));
}
}
}
public class SaleTicketBySynchronized {
public static void main(String[] args) {
Ticket ticket=new Ticket();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 40; i++) {
ticket.sale();
}
}
},"aa").start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 40; i++) {
ticket.sale();
}
}
},"bb").start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 40; i++) {
ticket.sale();
}
}
},"cc").start();
}
}
为锁和等待条件提供一个框架的接口和类,它不同于内置同步和监视器。
Lock 实现提供了比使用synchronized方法和语句可获得的更广泛的锁定操作。
Lock和synchronized有一点非常大的不同,采用synchronized不需要用户去手动释放锁,当synchronized方法或者synchronized 代码块执行完或者出现异常之后系统会自动让线程释放对锁的占用;而Lock则必须要用户去手动释放锁,如果没有主动释放锁,就有可能导致出现死锁现象。
3个售票员 卖出30张票
import java.util.concurrent.locks.ReentrantLock;
class Ticket{
private int num =30;
private final ReentrantLock lock=new ReentrantLock();
public void sale(){
//上锁
lock.lock();
try {
if(num>0){
System.out.println(Thread.currentThread().getName()+"卖出,"+"剩余:"+(--num));
}
}finally {
//解锁
lock.unlock();
}
}
}
public class SaleTicketByLock {
public static void main(String[] args) {
Ticket ticket=new Ticket();
new Thread(()-> {
for (int i = 0; i < 40; i++) {
ticket.sale();
}
},"aa").start();
new Thread(()-> {
for (int i = 0; i < 40; i++) {
ticket.sale();
}
},"bb").start();
new Thread(()-> {
for (int i = 0; i < 40; i++) {
ticket.sale();
}
},"cc").start();
}
}
有一个数开始为0 两个线程 不断+1-1
class Share{
private int number=0;
//+1
public synchronized void incr() throws InterruptedException {
if(number!=0){
this.wait();
}
number++;
System.out.println(Thread.currentThread().getName()+"::"+number);
//通知其他线程
this.notifyAll();
}
//-1
public synchronized void decr() throws InterruptedException {
if(number!=1){
this.wait();
}
number--;
System.out.println(Thread.currentThread().getName()+"::"+number);
//通知其他线程
this.notifyAll();
}
}
public class ThreadDemo01 {
public static void main(String[] args) {
Share share=new Share();
new Thread(()-> {
for (int i = 0; i < 10; i++) {
try {
share.incr();//+1
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"aa").start();
new Thread(()-> {
for (int i = 0; i < 10; i++) {
try {
share.decr();//-1
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"bb").start();
}
}
在案例中增加两个新线程 也是一加一减 cc dd
此时数据就会混乱
原因 wait执行时 被唤醒会继续执行(在哪里睡,就在哪里醒)恰巧又是两个加的线程抢到执行权 此时数据就会混乱
解决 将if 替换为while 不管怎么被唤醒都要执行判断
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class Share{
private int number=0;
private Lock lock=new ReentrantLock();
private Condition condition=lock.newCondition();
//+1
public void incr() throws InterruptedException {
lock.lock();
try {
while (number!=0){
condition.await();
}
number++;
System.out.println(Thread.currentThread().getName()+"::"+number);
//通知其他线程
condition.signalAll();
}finally {
lock.unlock();
}
}
//-1
public void decr() throws InterruptedException {
lock.lock();
try {
while (number!=1){
condition.await();
}
number--;
System.out.println(Thread.currentThread().getName()+"::"+number);
//通知其他线程
condition.signalAll();
}finally {
lock.unlock();
}
}
}
public class ThreadDemo02 {
public static void main(String[] args) {
Share share=new Share();
new Thread(()-> {
for (int i = 0; i < 10; i++) {
try {
share.incr();//-1
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"aa").start();
new Thread(()-> {
for (int i = 0; i < 10; i++) {
try {
share.decr();//-1
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"bb").start();
new Thread(()-> {
for (int i = 0; i < 10; i++) {
try {
share.incr();//-1
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"cc").start();
new Thread(()-> {
for (int i = 0; i < 10; i++) {
try {
share.decr();//-1
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"dd").start();
}
}
启动三个线程,按照如下要求:
AA打印5次后,BB打印10次后,CC打印15次 循环10次
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class ShareResource{
//1->aa 2->bb 3->bb
private int flag=1;
private Lock lock=new ReentrantLock();
private Condition c1=lock.newCondition();
private Condition c2=lock.newCondition();
private Condition c3=lock.newCondition();
public void print5(int loop) throws InterruptedException {
lock.lock();
try {
while (flag!=1){
c1.await();
}
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName()+"::"+i+":: 轮数:"+loop);
}
flag=2;
//通知线程
c2.signal();
}finally {
lock.unlock();
}
}
public void print10(int loop) throws InterruptedException {
lock.lock();
try {
while (flag!=2){
c2.await();
}
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+"::"+i+":: 轮数:"+loop);
}
flag=3;
//通知线程
c3.signal();
}finally {
lock.unlock();
}
}
public void print15(int loop) throws InterruptedException {
lock.lock();
try {
while (flag!=3){
c3.await();
}
for (int i = 0; i < 15; i++) {
System.out.println(Thread.currentThread().getName()+"::"+i+":: 轮数:"+loop);
}
flag=1;
//通知线程
c1.signal();
}finally {
lock.unlock();
}
}
}
public class ThreadDemo03 {
public static void main(String[] args) {
ShareResource shareResource=new ShareResource();
new Thread(()-> {
for (int i = 0; i < 10; i++) {
try {
shareResource.print5(i);//-1
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"aa").start();
new Thread(()-> {
for (int i = 0; i < 10; i++) {
try {
shareResource.print10(i);//-1
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"bb").start();
new Thread(()-> {
for (int i = 0; i < 10; i++) {
try {
shareResource.print15(i);//-1
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"cc").start();
}
}
import java.util.ArrayList;
import java.util.UUID;
public class ThreadDemo04 {
public static void main(String[] args) {
ArrayList<String> arrayList=new ArrayList();
for (int i = 1; i < 10; i++) {
new Thread(()-> {
arrayList.add(UUID.randomUUID().toString().substring(0,8));
System.out.println(arrayList);
},String.valueOf(i)).start();
}
}
}
Vector源码在添加时使用了synchronized
关键字 因此效率会低很多
import java.util.ArrayList;
import java.util.UUID;
import java.util.Vector;
public class ThreadDemo04 {
public static void main(String[] args) {
//ArrayList arrayList=new ArrayList();
Vector<String> arrayList=new Vector<>();
for (int i = 1; i < 10; i++) {
new Thread(()-> {
arrayList.add(UUID.randomUUID().toString().substring(0,8));
System.out.println(arrayList);
},String.valueOf(i)).start();
}
}
}
在定义的时候使用了synchronized
关键字 因此效率会低很多
import java.util.*;
public class ThreadDemo04 {
public static void main(String[] args) {
//ArrayList arrayList=new ArrayList();
//Vector arrayList=new Vector<>();
List<String> arrayList=Collections.synchronizedList(new ArrayList());
for (int i = 1; i < 10; i++) {
new Thread(()-> {
arrayList.add(UUID.randomUUID().toString().substring(0,8));
System.out.println(arrayList);
},String.valueOf(i)).start();
}
}
}
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
public class ThreadDemo04 {
public static void main(String[] args) {
//ArrayList arrayList=new ArrayList();
//Vector arrayList=new Vector<>();
//List arrayList=Collections.synchronizedList(new ArrayList());
List<String> arrayList = new CopyOnWriteArrayList();
for (int i = 1; i < 10; i++) {
new Thread(()-> {
arrayList.add(UUID.randomUUID().toString().substring(0,8));
System.out.println(arrayList);
},String.valueOf(i)).start();
}
}
}
import java.util.*;
public class ThreadDemo04 {
public static void main(String[] args) {
HashSet<String> set=new HashSet<>();
for (int i = 1; i < 50; i++) {
new Thread(()-> {
set.add(UUID.randomUUID().toString().substring(0,8));
System.out.println(set);
},String.valueOf(i)).start();
}
}
}
import java.util.*;
import java.util.concurrent.CopyOnWriteArraySet;
public class ThreadDemo04 {
public static void main(String[] args) {
Set<String> set=new CopyOnWriteArraySet<>();
for (int i = 1; i < 50; i++) {
new Thread(()-> {
set.add(UUID.randomUUID().toString().substring(0,8));
System.out.println(set);
},String.valueOf(i)).start();
}
}
}
import java.util.*;
public class ThreadDemo04 {
public static void main(String[] args) {
Map<String,String> set=new HashMap<>();
for (int i = 1; i < 50; i++) {
new Thread(()-> {
set.put(UUID.randomUUID().toString().substring(0,8),"nacl");
System.out.println(set);
},String.valueOf(i)).start();
}
}
}
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
public class ThreadDemo04 {
public static void main(String[] args) {
Map<String,String> set=new ConcurrentHashMap<>();
for (int i = 1; i < 50; i++) {
new Thread(()-> {
set.put(UUID.randomUUID().toString().substring(0,8),"nacl");
System.out.println(set);
},String.valueOf(i)).start();
}
}
}