线程与任务的关系
脱离了任务的线程是没有意义的
线程对象是通过Thread类来创建的
任务是通过Runnable接口来定义的
1.继承Thread类
2.实现Runnable接口
3.实现Callable接口 (与Runnable的区别,可以拿到返回值)
Thread线程执行的流程
线程一定要指定任务吗?
Thread构造器:无参构造器就是不需要指定任务,有参构造器可以直接指定线程的任务
public Thread(Runnable target) {
this(null, target, "Thread-" + nextThreadNum(), 0);
}
创建线程对象时候直接传入它的任务
流程:
public static void main( String[] args )
{
Thread thread = new Thread(() ->{
for (int i = 0; i < 10; i++){
System.out.println(i);
}
});
thread.start();
}
// Thread 的run方法
@Override
public void run() {
if (target != null) {
target.run(); // tager 传入的任务
}
}
Thread类中定义了一个Runnable tager成员变量,用来接受创建线程对象时,传入的任务
1. 创建线程对象,传入任务
2. 将任务赋值给tager成员变量
3. 线程执行的时候,操作tager成员变量
实现多线程的两种形式对比
public class MyThread extends Thread{
@Override
public void run() {
for(int i = 0; i < 10; i++){
System.out.println("----MyThread" + i);
}
}
}
public class App
{
public static void main( String[] args )
{
MyThread thread = new MyThread();
thread.start();
}
}
public class MyRunnable implements Runnable{
@Override
public void run() {
for (int i = 0; i < 10; i++){
System.out.println("myThread1:" + i);
}
}
}
public class MyRunnable2 implements Runnable{
@Override
public void run() {
for (int i = 0; i < 10; i++){
System.out.println("myThread2:" + i);
}
}
}
public class App
{
public static void main( String[] args )
{
Runnable runnable1 = new MyRunnable();
Runnable runnable2 = new MyRunnable2();
Thread thread = new Thread(runnable1);
thread.start();
Thread thread1 = new Thread(runnable2);
thread1.start();
}
}
线程休眠
创建t1对象并启动
t1休眠1秒
创建t2对象并启动
Thread t1 = new Thread(() ->{
for(int i = 0; i < 10; i++){
System.out.println(1);
}
});
t1.start();
try {
t1.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
Thread t2 = new Thread(()->{
for(int i = 0; i < 10; i ++){
System.out.println(2);
}
});
t2.start();
结果先输出10个1 在输出10个2
原因: sleep方法到底让哪个线程休眠
不在于谁调用sleep 而在于slepp写在哪 与调用者无关 (sleep 是静态方法信息)
放到t1里面 t1休眠
放在t2里面 t2休眠
基本实现使用, future+线程池异步多线程配合,能显著提高程序的执行效率
// 多线程/有返回值/异步任务
public class CompletableFutureDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTask futureTask = new FutureTask<>(new MyThreadCall());
Thread t1 = new Thread(futureTask, "t1");
t1.start();
System.out.println(futureTask.get());
}
}
class MyThreadCall implements Callable {
/**
* Computes a result, or throws an exception if unable to do so.
*
* @return computed result
* @throws Exception if unable to compute a result
*/
@Override
public String call() throws Exception {
System.out.println("come in call()");
return "hello callable";
}
}
// 结合线程池使用
public class FutureThreadPoolDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
Long startTime = System.currentTimeMillis();
ExecutorService threadPool = Executors.newFixedThreadPool(3);
FutureTask futureTask = new FutureTask<>(() -> {
try {
TimeUnit.MILLISECONDS.sleep(500);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return "task over";
});
threadPool.submit(futureTask);
FutureTask futureTask2 = new FutureTask<>(() -> {
try {
TimeUnit.MILLISECONDS.sleep(500);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return "task2 over";
});
threadPool.submit(futureTask2);
System.out.println(futureTask.get());
System.out.println(futureTask2.get());
try {
TimeUnit.MILLISECONDS.sleep(500);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
Long end = System.currentTimeMillis();
System.out.println("耗时" + (end - startTime));
threadPool.shutdown();
}
public void m1() {
// 3个任务 目前只有一个线程main处理,请问耗时多少
Long startTime = System.currentTimeMillis();
try {
TimeUnit.MILLISECONDS.sleep(300);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
try {
TimeUnit.MILLISECONDS.sleep(300);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
try {
TimeUnit.MILLISECONDS.sleep(500);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
Long end = System.currentTimeMillis();
System.out.println("耗时" + (end - startTime));
System.out.println(Thread.currentThread().getName());
}
}
public class FutureAPIDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException, TimeoutException {
FutureTask futureTask = new FutureTask<>(() -> {
try {
TimeUnit.MILLISECONDS.sleep(500);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return "task over";
});
Thread thread = new Thread(futureTask, "t1");
thread.start();
// System.out.println(futureTask.get()); // 会造成阻塞
System.out.println(Thread.currentThread().getName() + " " + "忙其他任务");
// System.out.println(futureTask.get()); // 等待返回值才结束程序
System.out.println(futureTask.get(3, TimeUnit.SECONDS)); // 等待3秒,如果没收到返回值,将抛出异常时间超时TimeoutException,并结束程序
}
}
缺点2 isDone 轮询
public class FutureAPIDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTask futureTask = new FutureTask<>(() -> {
try {
TimeUnit.MILLISECONDS.sleep(500);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return "task over";
});
Thread thread = new Thread(futureTask, "t1");
thread.start();
System.out.println(Thread.currentThread().getName() + " " + "忙其他任务");
while (true) {
if (futureTask.isDone()) {
System.out.println(futureTask.get());
break;
} else {
try {
TimeUnit.MILLISECONDS.sleep(500);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("还没好");
}
}
}
}
结论: Future对于结果的获取不是很友好,只能通过阻塞或者轮询的方式得到任务的结果
引言:
CompletableFuture 创建方法 // 官方建议,不推荐使用new CompletableFuture() 直接创建
没有指定Executor的方法,直接使用默认的ForkJoinPool.commonPool()作为它的线程池执行异步代码
如果指定线程池,则使用我们自定义的或者特别指定的线程池执行异步代码
1. 无返回值 无指定线程池,使用默认的线程池
public static CompletableFuture runAsync(Runnable runnable) {
return asyncRunStage(ASYNC_POOL, runnable);
}
2. 无返回值,指定线程池
public static CompletableFuture runAsync(Runnable runnable,
Executor executor) {
return asyncRunStage(screenExecutor(executor), runnable);
}
3. 有返回值,无指定线程池,使用默认的线程池
public static CompletableFuture supplyAsync(Supplier supplier) {
return asyncSupplyStage(ASYNC_POOL, supplier);
}
4. 有返回值,指定线程池
public static CompletableFuture supplyAsync(Supplier supplier,
Executor executor) {
return asyncSupplyStage(screenExecutor(executor), supplier);
}
// 补充:
CompletableFuture.get() 需要抛出异常,
CompletableFuture.join() 不需要抛出异常,
// 案例1
public class CompletableFutureBuildDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
// 官方建议,不推荐使用new CompletableFuture() 直接创建
CompletableFuture completableFuture = CompletableFuture.runAsync(() -> {
// 不指定线程池,得到的名字ForkJoinPool.commonPool-worker-19
System.out.println(Thread.currentThread().getName());
try {
TimeUnit.MILLISECONDS.sleep(500);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
});
// 结果输出为null
System.out.println(completableFuture.get());
}
}
// 案例2
public class CompletableFutureBuildDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
Executor executor = Executors.newFixedThreadPool(3);
CompletableFuture completableFuture = CompletableFuture.runAsync(() -> {
// 指定线程池 输出名字为pool-1-thread-1
System.out.println(Thread.currentThread().getName());
try {
TimeUnit.MILLISECONDS.sleep(500);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}, executor);
// 结果输出为null
System.out.println(completableFuture.get());
}
}
// 案例3
public class CompletableFutureBuildDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
CompletableFuture
// 线程返回结果是进入 传入线程返回的值和异常如下案例
public CompletableFuture whenComplete(
BiConsumer action) {
return uniWhenCompleteStage(null, action);
}
// 线程发生异常时进入, 用例如下
public CompletableFuture exceptionally(
Function fn) {
return uniExceptionallyStage(fn);
}
// 案例1 使用默认线程池
public class CompletableFutureUserDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
CompletableFuture supplyAsync = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + "----come in");
int result = ThreadLocalRandom.current().nextInt(10);
try {
TimeUnit.MILLISECONDS.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("-----1秒后出结果:" + result);
return result;
}).whenComplete((v, e) -> {
if (e == null) {
System.out.println("-------计算完成,更新updateValue:-------" + v);
}
}).exceptionally(e -> {
e.printStackTrace();
System.out.println("异常情况处理:" + e.getCause() + "\t" + e.getMessage());
return null;
});
System.out.println(Thread.currentThread().getName() + "---- 忙别的");
// 主线程不要立刻结束,否则CompletableFuture默认使用的线程池会立刻关闭,在暂停3秒种线程(与用户进程和守护进程相关)
try {
TimeUnit.MILLISECONDS.sleep(3000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
// 案例2 使用自定义线程池
public class CompletableFutureUserDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
// ExecutorService Executor的子类
ExecutorService executor = Executors.newFixedThreadPool(3);
try {
CompletableFuture supplyAsync = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + "----come in");
int result = ThreadLocalRandom.current().nextInt(10);
try {
TimeUnit.MILLISECONDS.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("-----1秒后出结果:" + result);
return result;
}, executor).whenComplete((v, e) -> {
if (e == null) {
System.out.println("-------计算完成,更新updateValue:-------" + v);
}
}).exceptionally(e -> {
e.printStackTrace();
System.out.println("异常情况处理:" + e.getCause() + "\t" + e.getMessage());
return null;
});
System.out.println(Thread.currentThread().getName() + "---- 忙别的");
} catch (Exception e) {
e.printStackTrace();
} finally {
executor.shutdown();
}
// 主线程不要立刻结束,否则CompletableFuture默认使用的线程池会立刻关闭,在暂停3秒种线程(与用户进程和守护进程相关) 使用自定义线程池无需卡主主线程
// try {
// TimeUnit.MILLISECONDS.sleep(3000);
// } catch (InterruptedException e) {
// throw new RuntimeException(e);
// }
}
}
// 案例三 异常处理
public class CompletableFutureUserDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
// ExecutorService Executor的子类
ExecutorService executor = Executors.newFixedThreadPool(3);
try {
CompletableFuture supplyAsync = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + "----come in");
int result = ThreadLocalRandom.current().nextInt(10);
// 创造异常
if (result > 5) {
int i = 10 / 0;
}
try {
TimeUnit.MILLISECONDS.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("-----1秒后出结果:" + result);
return result;
}, executor).whenComplete((v, e) -> {
if (e == null) {
System.out.println("-------计算完成,更新updateValue:-------" + v);
}
}).exceptionally(e -> {
e.printStackTrace();
System.out.println("异常情况处理:" + e.getCause() + "\t" + e.getMessage());
return null;
});
System.out.println(Thread.currentThread().getName() + "---- 忙别的");
} catch (Exception e) {
e.printStackTrace();
} finally {
executor.shutdown();
}
}
}
输出结果:
pool-1-thread-1----come in
main---- 忙别的
异常情况处理:java.lang.ArithmeticException: / by zero java.lang.ArithmeticException: / by zero
java.util.concurrent.CompletionException: java.lang.ArithmeticException: / by zero
... 3 more
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-S2MZ4DDv-1685244934310)(C:\Users\56964\AppData\Roaming\Typora\typora-user-images\1685107704454.png)]
/**
* 1需求说明
* 1.1同一款产品,同时搜索出同款产品在各大电商平台的售价;
* 1.2同一款产品,同时搜索出本产品在同一个电商平台下,各个入驻卖家售价是多少
* 2输出返回:
* 出来结果希望是同款产品的在不同地方的价格清单列表,返回一个List《mysql》 in jd price is 88.05
* 《mysql》 in dangdang price is 86.11《mysql》 in taobao price is 90.43
* 3解决方案,比对同一个商品在各个平台上的价格,要求获得一个清单列表,1 step by step,按部就班,查完京东查淘宝,查完淘宝查天猫…...…
* 2all in 万箭齐发,一口气多线程异步任务同时耸询。。 o o o
*
* @author cyh
* @Classname CompletableFutureMallDemo
* @Description TODO
* @Version 1.0.0
* @Date 2023/5/26 21:17
**/
public class CompletableFutureMallDemo {
static List netMallList = Arrays.asList(
new NetMall("jd"),
new NetMall("dangdang"),
new NetMall("taobao")
);
/**
* 一家家搜索 step by step
*
* @param list
* @param produceName
* @return
*/
public static List getPrice(List list, String produceName) {
return list
.stream()
.map(netMall ->
String.format(produceName + "in %s price is %.2f",
netMall.getNetMallName(),
netMall.calcPrice(produceName)))
.collect(Collectors.toList());
}
/**
* all in 万箭齐发,一口气多线程异步任务同时查询
*
* @param list
* @param produceName
* @return
*/
public static List getPriceByCompletableFuture(List list, String produceName) {
return list
.stream()
.map(netMall -> CompletableFuture.supplyAsync(() -> String.format(produceName + "in %s price is %.2f",
netMall.getNetMallName(),
netMall.calcPrice(produceName))))
.collect(Collectors.toList())// 先获取到List>
.stream() // 在对List>进行流处理获取join()得到List
.map(CompletableFuture::join)
.collect(Collectors.toList());
}
public static void main(String[] args) {
long startTime = System.currentTimeMillis();
List stringList = getPrice(netMallList, "MySQL");
stringList.forEach(System.out::println);
long endTime = System.currentTimeMillis();
System.out.println("-----step by step costTime:" + (endTime - startTime) + "毫秒");
long startTime2 = System.currentTimeMillis();
List stringList2 = getPriceByCompletableFuture(netMallList, "MySQL");
stringList2.forEach(System.out::println);
long endTime2 = System.currentTimeMillis();
System.out.println("-----all in costTime:" + (endTime2 - startTime2) + "毫秒");
}
}
@Data
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
class NetMall {
private String netMallName;
public Double calcPrice(String productName) {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
return ThreadLocalRandom.current().nextDouble() * 2 + productName.charAt(0);
}
}
返回值:
MySQLin jd price is 78.70
MySQLin dangdang price is 77.58
MySQLin taobao price is 77.41
-----step by step costTime:3050毫秒
MySQLin jd price is 77.39
MySQLin dangdang price is 77.71
MySQLin taobao price is 78.30
-----all in costTime:1012毫秒
public T get();
publie get(long timeout, TimeUnit unit);
publie T join();
public T getNow(T valueIfAbsent); 获取时线程未计算完成返回valueIfAbsent, 获取时已经计算完成则正常返回值,不会阻塞
public boolean complete(T value); 是否打断get方法立即返回括号值 无需抛出异常 线程计算未完成时,使用打断线程返回true,调用join()获取到的值为value, 线程计算完成调用方法,返回false,调用join()时返回线程返回的值
public class CompletableFutureAPIDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException, TimeoutException {
CompletableFuture future = CompletableFuture.supplyAsync(() -> {
try {
TimeUnit.MILLISECONDS.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return "abc";
});
System.out.println(future.get()); // 阻塞输出 abc
System.out.println(future.get(2L, TimeUnit.SECONDS)); //2秒内获取不到抛出异常,获取到输出abc
System.out.println(future.join()); // 无需处理异常。阻塞获取输出abc
try {
TimeUnit.MILLISECONDS.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(future.getNow("xxxxx")); // 调用时如果还没有计算完成,则输入xxxxx, 如果有返回值则输出abc
System.out.println(future.complete("completeValue") + "\t" + future.join()); // 是否打算计算,是返回true, join返回completeValue 否返回false, join得到abc
}
}
thenApply 计算结果存在依赖关系,这两个线程串行化
异常相关:由于存在依赖关系(当前步错,不走下一步), 当前步骤有异常的话就叫停
public class CompletableFutureAPIDemo {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(3);
try {
CompletableFuture.supplyAsync(() -> {
try {
TimeUnit.MILLISECONDS.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return 1;
}, executorService).thenApply(f -> f + 2).thenApply(f -> f + 3).whenComplete((v, e) -> {
if (e == null) {
System.out.println(v);
}
}).exceptionally(e -> {
e.printStackTrace();
return null;
});
} catch (Exception e) {
e.printStackTrace();
} finally {
executorService.shutdown();
}
}
}
handle 计算结果存在依赖关系,这两个线程串行化, 正常情况下 与thenApply一致
异常相关: 有异常也可以往下一步走,根据带的异常可以进入下一步处理
public class CompletableFutureAPIDemo {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(3);
try {
CompletableFuture.supplyAsync(() -> {
try {
TimeUnit.MILLISECONDS.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return 1;
}, executorService).handle((f, e) -> {
int i = 10 / 0;
return f + 2;
}).handle((f, e) -> {
if (e != null) {
return 3;
}
return f + 3;
}).whenComplete((v, e) -> {
if (e == null) {
System.out.println(v);
}
}).exceptionally(e -> {
e.printStackTrace();
return null;
});
} catch (Exception e) {
e.printStackTrace();
} finally {
executorService.shutdown();
}
}
}
thenAccept 接受任务的处理结果,并消费处理,无返回结果
public class CompletableFutureAPIDemo {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(3);
try {
CompletableFuture.supplyAsync(() -> {
try {
TimeUnit.MILLISECONDS.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return 1;
}, executorService)
.thenApply(f -> f + 2)
.thenApply(f -> f + 3)
.thenAccept(System.out::println);
} catch (Exception e) {
e.printStackTrace();
} finally {
executorService.shutdown();
}
}
}
对比:
applyToEither
public class CompletableFuturePoolDemo {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(5);
try {
CompletableFuture aComeIn = CompletableFuture.supplyAsync(() -> {
System.out.println("A come in");
try {
TimeUnit.MILLISECONDS.sleep(2000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return "resultA";
}, executorService);
CompletableFuture bComeIn = CompletableFuture.supplyAsync(() -> {
System.out.println("b come in");
try {
TimeUnit.MILLISECONDS.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return "resultB";
}, executorService);
CompletableFuture result = aComeIn.applyToEither(bComeIn, f -> f + " is winner");
System.out.println(result.join());
} catch (Exception e) {
e.printStackTrace();
} finally {
executorService.shutdown();
}
}
}
两个CompletionStage任务都完成后,最终能把两个任务的结果一起交给thenCombine来处理,先完成的先等着,等待其他分支任务。
public class CompletableFutureAPIDemo {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(3);
try {
CompletableFuture supplyAsync1 = CompletableFuture.supplyAsync(() -> {
System.out.println("1 come int");
try {
TimeUnit.MILLISECONDS.sleep(2000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return 10;
}, executorService);
CompletableFuture supplyAsync2 = CompletableFuture.supplyAsync(() -> {
System.out.println("2 come int");
try {
TimeUnit.MILLISECONDS.sleep(3000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return 30;
}, executorService);
CompletableFuture combine = supplyAsync1.thenCombine(supplyAsync2, (x, y) -> {
System.out.println("两个结果合并");
return x + y;
});
System.out.println(combine.join());
} catch (Exception e) {
e.printStackTrace();
} finally {
executorService.shutdown();
}
}
}
介绍:认为自己在使用数据时不会有别的线程修改数据或者资源,所以不会添加锁
在Java中是通过使用无锁编程来实现,只是在更新数据的时候去判断,之前有没有别的线程更新了这个数据
如果这个数据没有被更新,当前线程将自己修改的数据成功写入。
如果这个数据已经被其他线程更新,则根据不同的实现方式执行不用的操作,比如放弃修改,重试抢锁等等
判断规则:
适合场景:
/**
* 题目: 谈谈对多线程锁的理解,8锁案例说明
* 口诀: 线程, 操作, 资源类
* 8锁案例说明:
* 1 标准两个a, b线程,先打印发邮件还是短信 email sms
* 2. sendEmail方法加入暂停3秒钟,请问先打印邮件还是短信 email sms
* 3. 添加一个普通的hello方法,请问先打印邮件还是hello hello email
* 4. 有两部手机,请问先打印手机还是邮件 sms email
* 5. 有两个静态同步方法,有一部手机,请问先打印手机还是邮件 email sms
* 6. 有两个静态同步方法,有两部手机,请问先打印手机还是邮件 email sms
* 7. 有一个静态同步方法,有一个普通同步方法,有一部手机,请问先打印手机还是邮件 sms email
* 8. 有一个静态同步方法,有一个普通同步方法,有两部手机,请问先打印手机还是邮件 sms email
*
*
*
* 笔记总结:
* 1-2
* * * 一个对象里面如果有多个synchronized方法,某个时刻内,只要一个线程去调用其中一个synchronized方法了
* * * 其它线程都只能等待,换句话说,弄一个时刻内,只能有唯一的一个线程去访问这些synchronized方法
* * * 锁的是当前对象的this,被锁定后,其它的线程都不能进入到当前对象的其它的synchronized方法
* 3-4
* * * 加个普通方法后发现与同步锁无关
* * * 换成两个对象后,不是同一把锁了
* 5-6 都换成静态同步方法后,变成了类锁
* * * 三种synchronized锁的内容有一些差别
* * * 对于普通同步方法,锁的是当前实例对象,通常指this,具体的一部部手机,所有的普通同步方法用的都是同一把锁->实例对象本身本身
* * * 对于静态同步方法,锁的是当前类Class对象,如Phone.class唯一的一个模板
* * * 对于同步方法块,锁的是synchronized括号内的对象
* 7-8
* * * 当一个线程试图访问同步代码时它首先必须得到锁,正常退出或者抛出异常时必须释放锁
* * * 所有的普通同步方法用的都是同一把锁--实例对象本身,就是new出来的具体实例对象本身,本类this
* * * 也就是说,如果一个实例对象的普通同步方法获取锁后,该实例对象的其他普通同步方法必须等待获取锁的方法释放锁后才能获得锁
* * *
* * * 所有的静态同步方法用的也是 同一把锁--类本身,就是唯一模板Class
* * * 具体实例对象this和唯一模板Class, 这两把锁是两个不同的对象,所以静态同步方法与普通同步方法之间是不会有竞态条件的
* * * 但是一旦一个静态同步方法获得锁后,其他的静态同步方法都必须等待该方法释放锁后才能获得锁
*/
public class Lock8Demo {
public static void main(String[] args) {
Phone phone = new Phone();
Phone phone1 = new Phone();
new Thread(phone::sendEmail, "a").start();
try {
TimeUnit.MILLISECONDS.sleep(200);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
new Thread(() ->{
phone.sendSms();
phone1.hello();
}, "b").start();
}
}
class Phone {
public synchronized void sendEmail() {
try {
TimeUnit.MILLISECONDS.sleep(3000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("-----sendEmail");
}
public synchronized void sendSms() {
System.out.println("-----sendSms");
}
public static synchronized void sendEmail() {
try {
TimeUnit.MILLISECONDS.sleep(3000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("-----sendEmail");
}
public static synchronized void sendSms() {
System.out.println("-----sendSms");
}
public void hello() {
System.out.println("---------hello");
}
}