1 synchronized关键字
package thread;
import java.util.Random;
public class SyncSample {
public static void main(String[] args) {
Couplet c = new Couplet();
for(int i = 0 ; i < 10000 ; i++){
new Thread(){
public void run(){
int r = new Random().nextInt(2);
if(r % 2 == 0){
Couplet.first();
}else{
Couplet.second();
}
}
}.start();
}
}
}
class Couplet{
Object lock = new Object(); //锁对象
public synchronized static void first(){
// synchronized (lock) { //同步代码块,在同一时间只允许有一个线程执行访问这个方法
System.out.printf("琴");
System.out.printf("瑟");
System.out.printf("琵");
System.out.printf("琶");
System.out.println();
// }
}
public static void second(){
synchronized (Couplet.class) { //因为两个同步代码指向了同一把锁lock,所以在同一
个时间内只允许有一个代码块执行,其他等待
System.out.printf("魑");
System.out.printf("魅");
System.out.printf("魍");
System.out.printf("魉");
System.out.println();
}
}
}
package thread;2 死锁
import java.util.Random;
public class SyncSample {
public static void main(String[] args) {
Couplet c = new Couplet();
for(int i = 0 ; i < 10000 ; i++){
new Thread(){
public void run(){
int r = new Random().nextInt(2);
if(r % 2 == 0){
Couplet.first();
}else{
Couplet.second();
}
}
}.start();
}
}
}
class Couplet{
Object lock = new Object(); //锁对象
public synchronized static void first(){
// synchronized (lock) { //同步代码块,在同一时间只允许有一个线程执行访问这个方法
System.out.printf("琴");
System.out.printf("瑟");
System.out.printf("琵");
System.out.printf("琶");
System.out.println();
// }
}
public static void second(){
synchronized (Couplet.class) { //因为两个同步代码指向了同一把锁lock,所以在同一
个时间内只允许有一个代码块执行,其他等待
System.out.printf("魑");
System.out.printf("魅");
System.out.printf("魍");
System.out.printf("魉");
System.out.println();
}
}
}
package thread;
public class DeadLock {
private static String fileA = "A文件";
private static String fileB = "B文件";
public static void main(String[] args) {
new Thread(){ //线程1
public void run(){
while(true) {
synchronized (fileA) {//打开文件A,线程独占3 Thread的方式实现多线程
System.out.println(this.getName() + ":文件A写入");
synchronized (fileB) {
System.out.println(this.getName() + ":文件B写入");
}
System.out.println(this.getName() + ":所有文件保存");
}
}
}
}.start();
new Thread(){ //线程2
public void run(){
while(true) {
synchronized (fileB) {//打开文件A,线程独占
System.out.println(this.getName() + ":文件B写入");
synchronized (fileA) {
System.out.println(this.getName() + ":文件A写入");
}
System.out.println(this.getName() + ":所有文件保存");
}
}
}
}.start();
}
}
package com.itlaoqi.thread;
import java.util.Random;
/**
* 使用集成Thread的方式实现多线程
*/
public class Match1 {
public static void main(String[] args) {
Runner liuxiang = new Runner();//创建一个新的线程
liuxiang.setName("刘翔");//设置线程名称
Runner laoqi = new Runner();
laoqi.setName("老齐");
Runner op = new Runner();
op.setName("路飞");
liuxiang.start();//启动线程
laoqi.start();
op.start();
}
}
class Runner extends Thread{
@Override
public void run() {
Integer speed = new Random().nextInt(100);
for(int i = 1 ; i <= 100 ; i++){
try {4 Runnable方法实现多线程
Thread.sleep(1000); //当前线程休眠1秒
}catch (Exception e){
e.printStackTrace();
}
//this.getName()打印当前线程的名字
System.out.println(this.getName() + "已前进" + (i * speed) + "米(" +
speed + "米/秒)");
}
}
}
package com.itlaoqi.thread;
import java.util.Random;
public class Match2 {
public static void main(String[] args) {
Runner2 liuxiang = new Runner2();
Thread thread1 = new Thread(liuxiang);
thread1.setName("刘翔");
Thread laoqi = new Thread(new Runner2());
laoqi.setName("老齐");
Thread op = new Thread(new Runner2());
op.setName("路飞");
thread1.start();
laoqi.start();
op.start();
}
}
class Runner2 implements Runnable {
@Override
public void run() {
Integer speed = new Random().nextInt(100);
for(int i = 1 ; i <= 100 ; i++){
try {
Thread.sleep(1000); //当前线程休眠1秒
}catch (Exception e){
e.printStackTrace();
}
//Thread.currentThread()用于获取当前执行的线程对象
//在Runnable中是无法使用this获取到当前线程对象的
System.out.println(Thread.currentThread().getName() + "已前进" + (i *
speed) + "米(" + speed + "米/秒)");
}
}
}5 利用线程池实现线程
package thread;
import java.util.Random;
import java.util.concurrent.*;
public class Match3 {
public static void main(String[] args) throws ExecutionException,
InterruptedException {
//创建一个线程池。里面天生有3个“空”线程。Executors是调度器,对线程池进行管理
ExecutorService executorService = Executors.newFixedThreadPool(3);
Runner3 liuxiang = new Runner3();//实例化Callable对象
liuxiang.setName("刘翔");
Runner3 laoqi = new Runner3();
laoqi.setName("老齐");
Runner3 op = new Runner3();
op.setName("路飞");
//将这个对象扔到线程池中,线程池自动分配一个线程来运行liuxiang这个对象的call方法
//Future用于接受线程内部call方法的返回值
Future<Integer> result1 = executorService.submit(liuxiang);
Future<Integer> result2 = executorService.submit(laoqi);
Future<Integer> result3 = executorService.submit(op);
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
executorService.shutdown();//关闭线程池释放所有资源
System.out.println("刘翔累计跑了" + result1.get() + "米" );
System.out.println("老齐累计跑了" + result2.get() + "米" );
System.out.println("路飞累计跑了" + result3.get() + "米" );
}
}
class Runner3 implements Callable<Integer>{
private String name ;
public void setName(String name){
this.name = name;
}
//实现Callable接口可以允许我们的线程返回值或抛出异常
@Override
public Integer call() throws Exception {
Integer speed = new Random().nextInt(100);
Integer distince = 0; //总共奔跑的距离
for(int i = 1 ; i <= 100 ; i++){
Thread.sleep(10);
distince = i * speed;
System.out.println(this.name + "已前进" + distince + "米(" + speed +
"米/秒)");
}
return distince;
}6 可缓存线程池
7 定长线程池
}
package com.itlaoqi.juc;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolSample1 {
public static void main(String[] args) {
//调度器对象
//ExecutorService用于管理线程池
ExecutorService threadPool = Executors.newCachedThreadPool();//创建一个可
缓存线程池
//可缓存线程池的特点是,无限大,如果线程池中没有可用的线程则创建,有空闲线程则利用起来
for(int i = 1 ; i <= 1000 ; i++) {
final int index = i;
threadPool.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + ":" +
index);
}
});
}
try {
Thread.sleep(1000); //跟线程足够的运行时间
} catch (InterruptedException e) {
e.printStackTrace();
}
//shutdown() 代表关闭线程池(等待所有线程完成)
//shutdownNow() 代表立即终止线程池的运行,不等待线程,不推荐使用
threadPool.shutdown();
}
}
package com.itlaoqi.juc;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolSample2 {
public static void main(String[] args) {
//调度器对象
//ExecutorService用于管理线程池
ExecutorService threadPool = Executors.newFixedThreadPool(10);//创建一个可
创建一个定长线程池
//定长线程池的特点是固定线程总数,空间线程用于执行任务,如果线程都在使用后续任务则处于
等待状态,在线程池中的线程8 单线程池
//如果任务处于等待的状态,备选的等待算法默认为FIFO(先进先出) LIFO(后进先出)
//执行任务后再执行后续的任务。
for(int i = 1 ; i <= 1000 ; i++) {
final int index = i;
threadPool.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + ":" +
index);
}
});
}
try {
Thread.sleep(1000); //跟线程足够的运行时间
} catch (InterruptedException e) {
e.printStackTrace();
}
//shutdown() 代表关闭线程池(等待所有线程完成)
//shutdownNow() 代表立即终止线程池的运行,不等待线程,不推荐使用
threadPool.shutdown();
}
}
package com.itlaoqi.juc;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolSample3 {
public static void main(String[] args) {
//调度器对象
//ExecutorService用于管理线程池
ExecutorService threadPool = Executors.newSingleThreadExecutor();//单线程
线程池
for(int i = 1 ; i <= 1000 ; i++) {
final int index = i;
threadPool.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + ":" +
index);
}
});
}
try {
Thread.sleep(1000); //跟线程足够的运行时间
} catch (InterruptedException e) {
e.printStackTrace();
}
//shutdown() 代表关闭线程池(等待所有线程完成)
//shutdownNow() 代表立即终止线程池的运行,不等待线程,不推荐使用
threadPool.shutdown();
}
}9 可以调度的线程池
10 condition用于线程排序
我们在并行程序中,避免不了某些线程要预先规定好的顺序执行,
例如:先新增再修改,先买后卖,先进后出......,对于这类场景,使
用JUC的Condition对象再合适不过了。
u JUC中提供了Condition对象,用于让指定线程等待与唤醒,按预期
顺序执行。它必须和ReentrantLock重入锁配合使用。
u Condition用于替代wait()/notify()方法
– notify只能随机唤醒等待的线程,而Condition可以唤醒指定的线程,这有利于更好
的控制并发程序。
package com.itlaoqi.juc;
import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class
ThreadPoolSample4 {
public static void main(String[] args) {
ScheduledExecutorService scheduledThreadPool =
Executors.newScheduledThreadPool(5);//可调度线程池
/*//延迟三秒执行一次Run方法
scheduledThreadPool.schedule(new Runnable() {
@Override
public void run() {
System.out.println("延迟3秒执行");
}
} , 3 , TimeUnit.SECONDS);*/
//Timer , 项目实际开发中scheduledThreadPool与Timer都不会用到,应为有成熟的调度框
架Quartz,或者Spring自带调度,
//程序的调度框架支持一种表达式叫做Cron表达式,有兴趣的童鞋可以了解一下。
scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
System.out.println(new Date() + "延迟1秒执行,每三秒执行一次");
}
}, 1, 3, TimeUnit.SECONDS);
}
}
package juc;//测试唤醒操作
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class CoditionSample {
public static void main(String[] args) {
ReentrantLock lock=new ReentrantLock();//condition需要配合lock一起使用
Condition c2=lock.newCondition();
Condition c3=lock.newCondition();
Condition c1=lock.newCondition();
new Thread(new Runnable() {
@Override
public void run() {
try {
lock.lock();
Thread.sleep(1000);
c1.await(); //阻塞改线程 c1.singal的时候会被调用
System.out.println("粒粒也辛苦");
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
;
}).start();
new Thread(new Runnable() {
@Override
public void run() {
try {
lock.lock();
Thread.sleep(1000);
c3.await(); //阻塞改线程 c1.singal的时候会被调用
System.out.println("谁知盘中餐");
c1.signal();
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
try {
lock.lock();
c2.await(); //阻塞改线程 c1.singal的时候会被调用
Thread.sleep(1000);1 1 cyclicBarrier循环屏障
CyclicBarrier是一个同步工具类,它允许一组线程互相等
待,直到到达某个公共屏障点。与CountDownLatch不同
的是该barrier在释放等待线程后可以重用,所以称它为循
环(Cyclic)的屏障(Barrier)
System.out.println("汗滴和下土");
c3.signal();
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
lock.lock();
try {
Thread.sleep(1000);
System.out.println("锄禾日当午");
c2.signal();
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
}).start();
}
}
package juc;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CyclicBarrierSample {
private static CyclicBarrier cyclicBarrier = new CyclicBarrier(5);12 CountDownLatch - 倒计时锁
CountDownLatch倒计时锁特别适合”总-分任务”,
例如多线程计算后的数据汇总
u CountDownLatch类位于java.util.concurrent
(J.U.C)**包下,利用它可以实现类似计数器的功能。**
比如有一个任务A,它要等待其他3个任务执行完毕之
后才能执行,此时就可以利用CountDownLatch来实
现这种功能了
public static void main(String[] args) {
ExecutorService executorService = Executors.newCachedThreadPool();
for(int i = 1 ; i<=20 ; i++) {
final int index = i;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
executorService.execute(new Runnable() {
@Override
public void run() {
go();
}
});
}
executorService.shutdown();
}
private static void go(){
System.out.println(Thread.currentThread().getName() + ":准备就绪" );
try {
cyclicBarrier.await();//设置屏障点,当累计5个线程都准备好后,才运行后面的代码
System.out.println(Thread.currentThread().getName() + ":开始运行");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}
package juc;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CountDownSample {13 信号量
Semaphore信号量经常用于限制获取某种资源的线程数量。下面举个例子,
比如说操场上有5个跑道,一个跑道一次只能有一个学生在上面跑步,一旦
所有跑道在使用,那么后面的学生就需要等待,直到有一个学生不跑了
private static int count = 0;
public static void main(String[] args) {
ExecutorService threadPool = Executors.newFixedThreadPool(100);
CountDownLatch cdl = new CountDownLatch(10000); //CDL总数和操作数保持一致
for(int i = 1 ; i <= 10000 ; i++) {
final int index = i;
threadPool.execute(new Runnable() {
@Override
public void run() {
synchronized (CountDownSample.class) {
try {
count = count + index;
//计数器减一
}catch(Exception e){
e.printStackTrace();
}finally {
cdl.countDown();
}
}
}
});
}
/* try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}*/
try {
cdl.await(); //堵塞当前线程,知道cdl=0的时候再继续往下走
//为了避免程序一致挂起,我们可以设置一个timeout时间
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(count);
threadPool.shutdown();
}
}
package juc;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
public class SemaphoreSample1 {
public static void main(String[] args) {
ExecutorService threadPool = Executors.newCachedThreadPool();14 Callable&Future
Callable和Runnable一样代表着任务,区别在于**
Callable有返回值并且可以抛出异常。
Future 是一个接口。它用于表示异步计算的结果。提
供了检查计算是否完成的方法,以等待计算的完成,
并获取计算的结果
Semaphore semaphore = new Semaphore(5);//定义5个信号量,也就是说服务器只允许5
个人在里面玩
for(int i = 1 ; i <= 20 ; i++) {
final int index = i;
threadPool.execute(new Runnable() {
@Override
public void run() {
try {
semaphore.acquire();//获取一个信号量,“占用一个跑到”
play();
semaphore.release();//执行完成后释放这个信号量,“从跑道出去”
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
threadPool.shutdown();
}
public static void play(){
try {
System.out.println(new Date() + " " +
Thread.currentThread().getName() + ":获得紫禁之巅服务器进入资格");
Thread.sleep(2000);
System.out.println(new Date() + " " +
Thread.currentThread().getName() + ":退出服务器");
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
package juc;
import com.sun.org.apache.xpath.internal.operations.Bool;
import java.util.concurrent.*;
public class FutureSample {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(10);15 重入锁
重入锁是指任意线程在获取到锁之后,再次获取该锁而不会被该锁
所阻塞
ReentrantLock设计的目标是用来替代synchronized关键字
for(int i = 2 ; i <= 10000 ; i++){
Computor c = new Computor();
c.setNum(i);
//Future是对用于计算的线程进行监听,因为计算是在其他线程中执行的,所以这个返回结
果的过程是异步的
Future<Boolean> result = executorService.submit(c);//将c对象提交给线程
池,如有空闲线程立即执行里面的call方法
try {
Boolean r = result.get(); //用于获取返回值,如果线程内部的call没有执行
完成,则进入等待状态,直到计算完成
if(r == true){
System.out.println(c.getNum());
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
executorService.shutdown();
}
}
class Computor implements Callable<Boolean>{
private Integer num;
public Integer getNum() {
return num;
}
public void setNum(Integer num) {
this.num = num;
}
@Override
public Boolean call() throws Exception {
boolean isprime = true;
for(int i = 2 ; i < num ; i++) {
if (num % i == 0) {
isprime = false;
break;
}
}
return isprime;
}
}16 juc之并发容器
ArrayList -> CopyOnWriteArrayList - 写复制列表
package com.itlaoqi.juc;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockSample {
public static int users = 100;//同时模拟的并发访问用户数量
public static int downTotal = 50000; //用户下载的真实总数
public static int count = 0 ;//计数器
private static ReentrantLock lock = new ReentrantLock();
public static void main(String[] args) {
//调度器,JDK1.5后提供的concurrent包对于并发的支持
ExecutorService executorService = Executors.newCachedThreadPool();
//信号量,用于模拟并发的人数
final Semaphore semaphore = new Semaphore(users);
for(int i = 0 ; i < downTotal ; i++){
executorService.execute(()->{
//通过多线程模拟N个用户并发访问并下载
try {
semaphore.acquire();
add();
semaphore.release();
} catch (Exception e) {
e.printStackTrace();
}
});
}
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
executorService.shutdown();//关闭调度服务
System.out.println("下载总数:" + count);
}
//线程不安全
public static void add(){
lock.lock();//上锁
try {
count++;
}finally {
lock.unlock(); //解锁,一定要放在finally里面否则会出现死锁
}
}
}u HashSet -> CopyOnWriteArraySet - 写复制集合
u HashMap -> ConcurrentHashMap - 分段锁映射
package juc;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
public class ConcurrentHashMapSample {
public static int users = 100;//同时模拟的并发访问用户数量
public static int downTotal = 50000; //用户下载的真实总数
public static ConcurrentHashMap count = new ConcurrentHashMap() ;//计数器
public static void main(String[] args) {
ExecutorService executorService = Executors.newCachedThreadPool();
final Semaphore semaphore = new Semaphore(users);
for(int i = 0 ; i < downTotal ; i++){
final Integer index = i;
executorService.execute(()->{
//通过多线程模拟N个用户并发访问并下载
try {
semaphore.acquire();
count.put(index, index);
semaphore.release();
} catch (Exception e) {
e.printStackTrace();
}
});
}
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
executorService.shutdown();//关闭调度服务
System.out.println("下载总数:" + count.size());
}
}
写复制列表
package juc;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
public class CopyOnWriteArrayListSample {17 cas算法和乐观锁
原子性:是指一个操作或多个操作要么全部执行,且
执行的过程不会被任何因素打断,要么就都不执行
Atomic常用类
– AtomicInteger
– AtomicIntegerArray
– AtomicBoolean
– AtomicLong
– AtomicLongArray
public static void main(String[] args) {
//写复制列表
List<Integer> list = new CopyOnWriteArrayList<>();
for(int i = 0 ; i < 1000 ; i++){
list.add(i);
}
Iterator<Integer> itr = list.iterator();
while (itr.hasNext()) {
Integer i = itr.next();
list.remove(i);
}
System.out.println(list);
}
}
package juc;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicInteger;
public class AtomicIntegerSample {
public static int users = 100;//同时模拟的并发访问用户数量
public static int downTotal = 50000; //用户下载的真实总数
public static AtomicInteger count = new AtomicInteger() ;//计数器
public static void main(String[] args) {
//调度器,JDK1.5后提供的concurrent包对于并发的支持
ExecutorService executorService = Executors.newCachedThreadPool();
//信号量,用于模拟并发的人数
final Semaphore semaphore = new Semaphore(users);
for(int i = 0 ; i < downTotal ; i++){
executorService.execute(()->{
//通过多线程模拟N个用户并发访问并下载
try {
semaphore.acquire();add();
semaphore.release();
} catch (Exception e) {
e.printStackTrace();
}
});
}
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
executorService.shutdown();//关闭调度服务
System.out.println("下载总数:" + count);
}
//线程不安全
public static void add(){
count.getAndIncrement(); //count++
}
/*线程安全
public synchronized static void add(){
count++;
}*/
}