JUC:java.util.concurrent包,简称JUC。作者是美国Doug Lea。
一、进程与线程进程:进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动,它是操作系统动态执行的基本单元,在传统的操作系统中,进程既是基本的分配单元,也是基本的执行单元。
线程:通常在一个进程中可以包含若干个线程,当然一个进程中至少有一个线程,线程可以利用进程所拥有的资源,在引入线程的操作系统中,通常都是把进程作为分配资源的基本单位,而把线程作为独立运行和独立调度的基本单位。
二、并行与并发并行:指在同一时刻,有多条指令在多个处理器上同时执行。所以无论从微观还是从宏观来看,二者都是一起执行的。
并发:指在同一时刻只能有一条指令执行,但多个进程指令被快速的轮换执行,使得在宏观上具有多个进程同时执行的效果,但在微观上并不是同时执行的,只是把时间分成若干段,使多个进程快速交替的执行
三、创建线程的三种方式 1、继承Thread类public class TortoiseThread extends Thread{
@Override
public void run() {
while(true){
System.out.println(this.getName()+" "+this.getPriority()+"乌龟领先了,加油!");
}
}
}
public class Test {
public static void main(String[] args) {
//乌龟
Runnable target;
Thread thread = new TortoiseThread();
//thread.run(); //运行方法
thread.start(); //启动线程
//兔子
while(true){
System.out.println(Thread.currentThread().getName()+" "
+Thread.currentThread().getPriority()+"兔子领先了,加油!");
}
}
}
2、实现Runnable接口
public class TortoiseRunnable implements Runnable{
@Override
public void run() {
while(true){
System.out.println(Thread.currentThread().getName()+" "
+Thread.currentThread().getPriority()+"乌龟领先了,加油");
}
}
}
public class Test {
public static void main(String[] args) {
Thread.currentThread().setName("兔子线程");
Thread.currentThread().setPriority(8);
//乌龟
Runnable runnable = new TortoiseRunnable();
Thread thread = new Thread(runnable,"乌龟线程");
thread.setPriority(10);
thread.setName("乌龟线程");
thread.start(); //启动线程
//兔子
while(true){
System.out.println(Thread.currentThread().getName()+" "
+Thread.currentThread().getPriority()+"兔子领先了,加油!");
}
}
}
3、实现Callable接口
public class MyCallable implements Callable{ @Override public Integer call() throws Exception { Thread.sleep(5000); TimeUnit.SECONDS.sleep(5); return new Random().nextInt(10); } public static void main(String[] args) throws ExecutionException, InterruptedException, TimeoutException { Callable callable = new MyCallable(); FutureTask futureTask = new FutureTask(callable); Thread thread = new Thread(futureTask); thread.start(); System.out.println(futureTask.isDone()); Integer result = futureTask.get(); //阻塞直到得到结果 //Integer result = futureTask.get(3,TimeUnit.SECONDS); //只等3秒 System.out.println(futureTask.isDone()); System.out.println(result); } }
public class TestCallable {
public static void main(String[] args) throws ExecutionException, InterruptedException {
Callable callable =()->{
return new Random().nextInt(10);
};
FutureTask task = new FutureTask(()->{
return new Random().nextInt(10);
});
new Thread(task).start();
Integer result = task.get();
System.out.println(result);
}
}
**Runnable接口与Callable接口的区别**:
相同点:都是接口,都可以编写多线程程序,窦彩勇Thread.start()启动线程
不同点: ①具体方法不同,一个是run,一个是call
②Runnable没有返回值,Callable可以返回执行结果,是个泛型
③Callable接口的call()方法允许抛出异常;Runnable的run()方法异常只能在内部消化,不能往上继续抛<可以将检查时异常转化为运行时异常抛出>
④Callable接口提供了检查计算是否完成的方法,以等待计算的完成,并检索计算的结果。
四、锁 (线程同步)(1)无锁售票
class Ticket{
private Integer num = 200;
public Integer getNum(){
return num;
}
public void sale(){
//无票可卖
if(num<=0){
return;
}
System.out.println(Thread.currentThread().getName()+"开始卖票,"+num);
try {
Thread.sleep(10); //当前线程让出CPU进入阻塞状态,其他线程就会获取CPU,为了模拟线程切换,暴露线程同步问题
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"卖票完毕,还剩"+--num);
}
}
public class SaleTicket {
public static void main(String[] args) {
Ticket ticket = new Ticket();
Runnable runnable = ()->{
while(true){
ticket.sale();
if(ticket.getNum()<=0){
break;
}
}
};
//三个卖票窗口
new Thread(runnable,"AAA").start();
new Thread(runnable,"BBB").start();
new Thread(runnable,"CCC").start();
}
}
(2)同步锁 synchronized
如果执行完毕或者线程执行异常,JVM会自动释放锁
①同步代码块
class Ticket{
private Integer num = 20;
public Integer getNum(){
return num;
}
public void sale(){
//此处省略100句
synchronized (this){ //同步监视器 this==Ticket
//无票可卖
if(num<=0){
return;
}
System.out.println(Thread.currentThread().getName()+"开始卖票,"+num);
try {
Thread.sleep(10); //当前线程让出CPU进入阻塞状态,其他线程就会获取CPU,为了模拟线程切换,暴露线程同步问题
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"卖票完毕,还剩"+--num);
}
//此处省略50句
}
}
public class SaleTicket {
public static void main(String[] args) {
Ticket ticket = new Ticket();
Runnable runnable = ()->{
while(true){
ticket.sale();
if(ticket.getNum()<=0){
break;
}
}
};
//三个卖票窗口
new Thread(runnable,"AAA").start();
new Thread(runnable,"BBB").start();
new Thread(runnable,"CCC").start();
}
}
②同步方法
class Ticket{
private Integer num = 200;
public Integer getNum(){
return num;
}
public synchronized void sale(){ //实例方法同步监视器是this(存在于堆中);如果是static方法,同步监视器是Ticket.class(存在于方法区中)
//此处省略100句
//无票可卖,退出程序
if(num<=0){
return;
}
System.out.println(Thread.currentThread().getName()+"开始卖票,"+num);
try {
Thread.sleep(10); //当前线程让出CPU进入阻塞状态,其他线程就会获取CPU,为了模拟线程切换,暴露线程同步问题
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"卖票完毕,还剩"+--num);
//此处省略50句
}
}
public class SaleTicket {
public static void main(String[] args) {
Ticket ticket = new Ticket();
Runnable runnable = ()->{
while(true){
ticket.sale();
if(ticket.getNum()<=0){
break;
}
}
};
//三个卖票窗口
new Thread(runnable,"AAA").start();
new Thread(runnable,"BBB").start();
new Thread(runnable,"CCC").start();
}
}
同步代码块的效率要比同步方法的效率高
(3)lock锁
(4)可重入锁 ReentrantLock



