线程Thread 的三种创建与应用
java 三种线程的创建
1、Thread类
三部曲:
①继承Thread类
②重写run()方法
③创建该线程的实例,调用start()方法开启线程
具体实现如下:
1.1 Thread 实现
package demo.thread;
// 继承Thread 类
public class thread01 extends Thread{
// 重写run()方法
@Override
public void run(){
for (int i = 0; i < 100; i++) {
System.out.println("run()运行了" + i);
}
}
public static void main(String[] args) {
// 主函数内创建类的实例,调用start()方法开启线程
thread01 thread01 = new thread01();
thread01.start();
for (int i = 0; i < 100; i++) {
System.out.println("thread 开启" +i);
}
}
}
1.2 Thread 下载网图
现在使用Thread线程实现一个网络图片的下载,代码如下:
在这里需要导入一个commons.io的jar包
网络上下载这个jar包后,在目录上建一个lib的目录,将目录添加为库,就可以使用jar包下的函数了。
package demo.thread;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
public class thread02 extends Thread{
private String url;
private String name;
public thread02(String url, String name) {
this.url = url;
this.name = name;
}
@Override
public void run(){
WebDownLoad webDownLoad = new WebDownLoad();
webDownLoad.download(url,name);
System.out.println("下载了文件名为"+name+"文件");
}
public static void main(String[] args) {
// 下载并不是按照线程的顺序执行的,按照图片的大小来先后顺序。--多开几个线程,通过观察可以发现。
// 将下载的图片重新命名,放到img目录下
thread02 thread02 = new thread02("http://pic.bizhi360.com/bbpic/79/10079.jpg","img/girl.jpg");
thread02.start();
}
}
class WebDownLoad{
public void download(String url,String name){
try {
FileUtils.copyURLToFile(new URL(url),new File(name));
} catch (IOException e) {
e.printStackTrace();
System.out.println("IO 异常,download出现异常!");
}
}
}
1.3 以前的实现线程的方式和推荐的线程
旧的线程
package com.mao.demo01;
/**
* author 小毛桑
*
* @date 2021/10/10 0010 17:30
*/
// 老旧版的线程
// 线程是一个单独的资源类, 没有任何附属操作
public class SaleTicket{
public static void main(String[] args) {
new Thread(new MyThread()).start();
}
}
class MyThread implements Runnable{
@Override
public void run() {
}
}
*多线程会出现线程混乱的问题,可以使用Synchronized和Lock方法解决
具体如下:
1.4 Synchronized
package com.mao.demo01;
/**
* author 小毛桑
*
* @date 2021/10/10 0010 19:47
*/
public class SaleSaleTicket02 {
public static void main(String[] args) {
Ticket02 ticket = new Ticket02();
// 多线程争抢了资源
// 以前是B的Runnable的写法,A和C是现阶段推荐的写法
new Thread(()->{ for (int i = 1; i < 50; i++) ticket.sale(); },"A").start();
new Thread(new Runnable() {
@Override
public void run(){for (int i = 1; i < 50; i++) ticket.sale();}
},"B").start();
new Thread(()->{ for (int i = 1; i < 50; i++) ticket.sale(); },"C").start();
}
}
class Ticket02 {
private int tickets = 50;
// public void sale(){
// if (tickets > 0){
// System.out.println(Thread.currentThread().getName()+"卖出了第" + tickets-- +"张票,剩余了"+ tickets + "张票");
// }
// }
// synchronized 本质:排队
public synchronized void sale(){
if (tickets > 0){
System.out.println(Thread.currentThread().getName()+"卖出了第" + tickets-- +"张票,剩余了"+ tickets + "张票");
}
}
}
// 运行结果:
E:\IDEA\jbr\bin\java.exe -javaagent:
E:\IDEA\lib\idea_rt.jar=13500:
E:\IDEA\bin -Dfile.encoding=UTF-8 -classpath
E:\Code\Mybatis-Ex\JUC\target\classes;
E:\downLoad-Package\apache-maven-3.8.1\maven-repo\mysql\mysql-connector-java\5.1.47\mysql-connector-java-5.1.47.jar;
E:\downLoad-Package\apache-maven-3.8.1\maven-repo\org\mybatis\mybatis\3.5.2\mybatis-3.5.2.jar;
E:\downLoad-Package\apache-maven-3.8.1\mavenrepo\junit\junit\4.12\junit-4.12.jar;
E:\downLoad-Package\apache-maven-3.8.1\maven-repo\org\hamcrest\hamcrest-core\1.3\hamcrest-core-1.3.jar;
E:\downLoad-Package\apache-maven-3.8.1\mavenrepo\org\projectlombok\lombok\1.18.20\lombok-1.18.20.jar com.mao.demo01.SaleSaleTicket02
A卖出了第50张票,剩余了49张票
A卖出了第49张票,剩余了48张票
A卖出了第48张票,剩余了47张票
A卖出了第47张票,剩余了46张票
A卖出了第46张票,剩余了45张票
A卖出了第45张票,剩余了44张票
A卖出了第44张票,剩余了43张票
A卖出了第43张票,剩余了42张票
A卖出了第42张票,剩余了41张票
A卖出了第41张票,剩余了40张票
A卖出了第40张票,剩余了39张票
A卖出了第39张票,剩余了38张票
A卖出了第38张票,剩余了37张票
A卖出了第37张票,剩余了36张票
A卖出了第36张票,剩余了35张票
A卖出了第35张票,剩余了34张票
A卖出了第34张票,剩余了33张票
A卖出了第33张票,剩余了32张票
A卖出了第32张票,剩余了31张票
A卖出了第31张票,剩余了30张票
A卖出了第30张票,剩余了29张票
A卖出了第29张票,剩余了28张票
A卖出了第28张票,剩余了27张票
A卖出了第27张票,剩余了26张票
A卖出了第26张票,剩余了25张票
A卖出了第25张票,剩余了24张票
A卖出了第24张票,剩余了23张票
A卖出了第23张票,剩余了22张票
A卖出了第22张票,剩余了21张票
A卖出了第21张票,剩余了20张票
A卖出了第20张票,剩余了19张票
A卖出了第19张票,剩余了18张票
A卖出了第18张票,剩余了17张票
A卖出了第17张票,剩余了16张票
A卖出了第16张票,剩余了15张票
A卖出了第15张票,剩余了14张票
A卖出了第14张票,剩余了13张票
A卖出了第13张票,剩余了12张票
A卖出了第12张票,剩余了11张票
A卖出了第11张票,剩余了10张票
A卖出了第10张票,剩余了9张票
A卖出了第9张票,剩余了8张票
A卖出了第8张票,剩余了7张票
A卖出了第7张票,剩余了6张票
A卖出了第6张票,剩余了5张票
A卖出了第5张票,剩余了4张票
A卖出了第4张票,剩余了3张票
A卖出了第3张票,剩余了2张票
A卖出了第2张票,剩余了1张票
C卖出了第1张票,剩余了0张票
进程已结束,退出代码为 0
1.5 Lock锁解决,结果和Synchronized的结果一致
package com.mao.demo01;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* author 小毛桑
*
* @date 2021/10/10 0010 20:06
*/
public class SaleTicketsLock {
public static void main(String[] args) {
TicketLock ticket = new TicketLock();
new Thread(()->{ for (int i = 1; i < 50; i++) ticket.sale(); },"小明").start();
new Thread(()->{ for (int i = 0; i < 50; i++) ticket.sale(); },"老白").start();
new Thread(()->{ for (int i = 1; i < 50; i++) ticket.sale(); },"小粉").start();
}
}
class TicketLock {
private int tickets = 50;
Lock lock = new ReentrantLock(true);
// 本质:排队
public void sale(){
lock.lock();
try {
if (tickets > 0){
System.out.println(Thread.currentThread().getName()+"卖出了第" + tickets-- +"张票,剩余了"+ tickets + "张票");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
1.6 Synchronized和Lock的区别
- Synchronized 是java内置关键字,Lock是java类
- Synchronized 无法判断获取锁的状态,Lock可以判断是否获取到锁
- Synchronized 会自动自动释放锁, Lock必须手动的释放锁,如果不释放锁,就会导致死锁
- Synchronized 线程1 堵塞,线程2堵塞下去,直到1释放(可重入锁,不可中断,非公平锁)
- Lock 不一等会一直等待下去(lock.tryLock())(可重入锁,可以判断锁,可自己设置)
- Lock lock = new ReentrantLock(true);公平锁
2、Runnable接口
三部曲:
①实现一个Runnable接口
②重写run()方法
③使用Thread有参构造方法实现创建线程的实例,并将Runnable接口的实现类的实例对象作为参数传入,调用线程实例的start()方法开启线程
具体实现如下:
2.1 Runnable实现
package demo.thread;
public class runnable01 implements Runnable{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("run()运行了" + i);
}
}
public static void main(String[] args) {
runnable01 runnable01 = new runnable01();
// 代理 Thread 也实现了一个Runnable接口
// Thread thread = new Thread(runnable01);
// thread.start();
new Thread(runnable01).start();
// 使用Thread有参构造方法实现创建线程的实例,并将Runnable接口的实现类的实例对象作为参数传入,调用线程实例的start()方法开启线程
for (int i = 0; i < 100; i++) {
System.out.println("Runnable 的 Thread 开启" +i);
}
}
}
2.2 写一个Runnable接口的售票案列
package demo.thread;
public class runnable02 implements Runnable{
private int tickets = 10;
@Override
public void run(){
while (true){
if (tickets <= 0){break;}
System.out.println(Thread.currentThread().getName()+"拿到了第"+ tickets -- +"张票");
}
// 线程延时 可以放大多线程的问题。可以通过synchronized 或者lock锁来解决
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
runnable02 runnable02 = new runnable02();
new Thread(runnable02,"---------").start();
new Thread(runnable02,"*********").start();
new Thread(runnable02,"¥¥¥¥¥¥").start();
}
}
2.3 两个线程的竞争模拟龟兔赛跑
通过线程的延迟,可以让乌龟永远的赢下去
package demo.thread;
public class runnable03 implements Runnable{
private String winner;
@Override
public void run() {
for (int i = 0; i <= 100; i++) {
// 模拟兔子睡觉
if (Thread.currentThread().getName().equals("兔子") && i %10 == 0){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
boolean flag = gameOver(i);
if (flag){break;}
System.out.println(Thread.currentThread().getName()+"======跑了"+i+"步");
}
}
private boolean gameOver(int steps){
if (winner!=null){return true;}
else {
if (steps >= 100){
winner = Thread.currentThread().getName();
System.out.println("胜利者"+ winner);
return true;
}
}
return false;
}
public static void main(String[] args) {
runnable03 runnable03 = new runnable03();
new Thread(runnable03,"兔子").start();
new Thread(runnable03,"乌龟").start();
}
}
3、Callable接口
三部曲:
①实现一个Callable接口
②重写call()方法
③
MyThread thread = new MyThread();
FutureTask<Integer> integerFutureTask = new FutureTask<>(thread);
new Thread(integerFutureTask).start();
3.1 Callable JDK8的文档说明:
在Runnable 的接口下有一个FutureTask 的类,在这个类的构造方法的重载中实现了调用Runnable 和 Callable 的方法。
3.2 Callable实现
package com.mao.callable;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
/**
* author 小毛桑
*
* @date 2021/10/16 0016 16:06
*/
public class CallableTest {
public static void main(String[] args) throws Exception{
MyThread thread = new MyThread();
FutureTask<Integer> integerFutureTask = new FutureTask<>(thread);
new Thread(integerFutureTask,"A").start();
new Thread(integerFutureTask,"B").start();//有缓存,效率高
Integer integer = integerFutureTask.get();// 结果需要等待,有阻塞, 放在最后一行,异步执行
System.out.println(integer);
}
}
class MyThread implements Callable<Integer> {
@Override
public Integer call() throws Exception {
System.out.println("AAA");
return 2048;
}
}
3.3 Callable 实现网图下载
package demo.thread;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.*;
public class callable01 implements Callable<Boolean> {
private String url;
private String name;
public callable01(String url, String name) {
this.url = url;
this.name = name;
}
@Override
public Boolean call() {
WebDownLoad webDownLoad = new WebDownLoad();
webDownLoad.download(url,name);
System.out.println("下载了文件名为"+name+"文件");
return true;
}
public static void main(String[] args) {
Callable c1 = new callable01("https://www.qqyunsd.com/wp-content/uploads/2021/09/%E6%9D%A8%E6%B8%85%E6%9F%A04k%E6%89%8B%E6%9C%BA%E5%A3%81%E7%BA%B8%E7%AB%96%E5%B1%8F%E7%BE%8E%E5%A5%B3-scaled.jpg", "img/girl1.jpg");
Callable c2 = new callable01("https://www.qqyunsd.com/wp-content/uploads/2021/10/%E6%8A%96%E9%9F%B34k%E7%BE%8E%E5%A5%B3%E5%A3%81%E7%BA%B8-scaled.jpg", "img/girl2.jpg");
Callable c3 = new callable01("https://www.qqyunsd.com/wp-content/uploads/2021/09/%E5%AE%B6%E5%B1%85-%E5%8F%AF%E7%88%B1%E5%B0%8F%E5%A7%90%E5%A7%90-%E4%BE%A7%E8%BA%BA-%E5%A5%BD%E7%9C%8B%E8%BA%AB%E6%9D%904k%E7%BE%8E%E5%A5%B3%E5%A3%81%E7%BA%B8-2048x1152.jpg", "img/girl3.jpg");
// 线程池
ExecutorService ser = Executors.newFixedThreadPool(3);
Future<Boolean> s1 = ser.submit(c1);
Future<Boolean> s2 = ser.submit(c2);
Future<Boolean> s3 = ser.submit(c3);
try {
Boolean a1 = s1.get();
Boolean a2 = s1.get();
Boolean a3 = s1.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
ser.shutdown();
}
}
class WebDownLoad{
public void download(String url,String name){
try {
FileUtils.copyURLToFile(new URL(url),new File(name));
} catch (IOException e) {
e.printStackTrace();
System.out.println("IO 异常,download出现异常!");
}
}
}
4、生产者与消费者
4.1 传统的的消费者与生产者
package com.mao.productAndCustomor;
/**
* author 小毛桑
*
* @date 2021/10/10 0010 21:49
*/
// 通知核等待唤醒
public class Pac {
public static void main(String[] args) {
Data data = new Data();
new Thread(()->{
for (int i = 0; i < 30; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"A").start();
new Thread(()->{
for (int i = 0; i < 30; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"B").start();
}
}
class Data{
private int number = 0;
public synchronized void increment() throws InterruptedException {
if (number != 0){
// 等待
this.wait();
}
// 唤醒
number++;
this.notifyAll();
System.out.println(Thread.currentThread().getName()+"-------->"+number);
}
public synchronized void decrement() throws InterruptedException {
if (number == 0){
// 等待
this.wait();
}
// 唤醒
number--;
this.notifyAll();
System.out.println(Thread.currentThread().getName()+"-------->"+number);
}
}
运行的结果:
A-------->1
B-------->0
A-------->1
B-------->0
A-------->1
B-------->0
A-------->1
B-------->0
...
问题: 如果大于两个线程,就会出现问题,如开四条线程:
new Thread(()->{
for (int i = 0; i < 30; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"A").start();
new Thread(()->{
for (int i = 0; i < 30; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"B").start();
// 只限制在两个线程,解决方法:
new Thread(()->{
for (int i = 0; i < 30; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"C").start();
new Thread(()->{
for (int i = 0; i < 30; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"D").start();
出现的问题:消费者过度的消费,虚假的唤醒if,应为if只能判断一次,以至于出现非0和1
4.2 虚假唤醒
解决方法:
// while 返回虚假唤醒
while (number != 0){
// 等待
this.wait();
}
jdk8中描述如下
4.3 JUC的生产者与消费者
四条线程
class Data{
private int number = 0;
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
public void increment() throws InterruptedException {
lock.lock();
try {
// while 返回虚假唤醒
while (number != 0){
// 等待
condition.await();
}
// 唤醒
number++;
System.out.println(Thread.currentThread().getName()+"-------->"+number);
condition.signalAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void decrement() throws InterruptedException {
lock.lock();
try {
while (number == 0){
// 等待
condition.await();
}
// 唤醒
number--;
System.out.println(Thread.currentThread().getName()+"-------->"+number);
condition.signalAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
有顺序的A–>B–>C–>D
class Data{
private Lock lock = new ReentrantLock();
// 精准的唤醒
private Condition condition1 = lock.newCondition();
private Condition condition2 = lock.newCondition();
private Condition condition3 = lock.newCondition();
private Condition condition4 = lock.newCondition();
private int number = 1;
public void printA(){
lock.lock();
try {
while (number != 1){condition1.await();}
number+=1;
System.out.println(Thread.currentThread().getName()+"---------->AAA ---number:"+ number);
condition2.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void printB(){
lock.lock();
try {
while (number != 2){condition2.await();}
number+=1;
System.out.println(Thread.currentThread().getName()+"---------->BBB ---number:"+ number);
condition3.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void printC(){
lock.lock();
try {
while (number != 3){condition3.await();}
number+=1;
System.out.println(Thread.currentThread().getName()+"---------->CCC ---number:"+ number);
condition4.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void printD(){
lock.lock();
try {
while (number !=4){condition4.await();}
number = 1;
System.out.println(Thread.currentThread().getName()+"---------->DDD ---number:"+ number);
condition1.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
开启线程:
Data data = new Data();
new Thread(()->{for (int i = 0; i < 20; i++) data.printA(); },"a").start();
new Thread(()->{for (int i = 0; i < 20; i++) data.printB(); },"b").start();
new Thread(()->{for (int i = 0; i < 20; i++) data.printC(); },"c").start();
new Thread(()->{for (int i = 0; i < 20; i++) data.printD(); },"d").start();
运行结果如下:
5、 8锁问题
问题一:两个普通的锁方法,new一个对象调用,调用过程中间睡1秒,执行结果是什么
代码如下:
package com.mao.lock8;
import java.util.concurrent.TimeUnit;
/**
* author 小毛桑
*
* @date 2021/10/20 0020 22:38
* 两个普通的锁方法,new一个对象调用,调用过程中间睡2秒,执行结果是什么
*/
public class lock1 {
public static void main(String[] args) throws InterruptedException {
People people = new People();
new Thread(()->{people.live();},"a").start();
TimeUnit.SECONDS.sleep(1);
new Thread(()->{people.dead();},"b").start();
}
}
class People{
public synchronized void live(){
System.out.println("活着");
}
public synchronized void dead(){
System.out.println("死亡");
}
}
问题一结果如下:
原因: 不是因为优先级,而是因为Synchronized锁(同步代码块),锁住了上面的people 对象。
运行结果如图
问题二:两个普通的锁方法,new一个对象调用,调用过程中间睡1秒,且在live方法中睡3秒,执行结果是什么
代码如下:
package com.mao.lock8;
import java.sql.Time;
import java.util.concurrent.TimeUnit;
/**
* author 小毛桑
*
* @date 2021/10/20 0020 22:57
*
* 两个普通的锁方法,new一个对象调用,调用过程中间睡1秒,且在live方法中睡3秒,执行结果是什么
*/
public class lock2 {
public static void main(String[] args) throws InterruptedException {
People people = new People();
new Thread(()->{people.live();},"a").start();
TimeUnit.SECONDS.sleep(1);
new Thread(()->{people.dead();},"b").start();
}
}
class People{
public synchronized void live() {
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("活着");
}
public synchronized void dead(){
System.out.println("死亡");
}
}
问题二结果如下:
原因: 因为Synchronized锁(同步代码块),锁住了上面的people 对象,并并且 锁住的是同一个对象。
运行结果如图
问题三:一个普通的锁方法,一个普通无锁方法,new一个对象调用,在live方法中睡3秒,执行结果是什么
package com.mao.lock8;
import java.util.concurrent.TimeUnit;
/**
* author 小毛桑
*
* 一个普通的锁方法,一个普通无锁方法,new一个对象调用,在live方法中睡3秒,执行结果是什么
* @date 2021/10/20 0020 23:07
*/
public class lock3 {
public static void main(String[] args) throws InterruptedException {
People people = new People();
new Thread(()->{people.live();},"a").start();
TimeUnit.SECONDS.sleep(1);
new Thread(()->{people.dead();},"b").start();
}
}
class People{
public synchronized void live() {
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("活着");
}
public void dead(){
System.out.println("死亡");
}
}
问题三结果如下:
原因: 因为Synchronized锁(同步代码块),锁住了上面的people 对象但是dead方法没有加锁,仅仅是普通方法.
运行结果如图
问题四:两个普通的锁方法,new两个对象分别调用,在live方法中睡3秒,执行结果是什么
package com.mao.lock8;
import java.util.concurrent.TimeUnit;
/**
* author 小毛桑
*
* @date 2021/10/20 0020 23:13
* **问题四:两个普通的锁方法,new两个对象分别调用,在live方法中睡3秒,执行结果是什么**
*/
public class lock4 {
public static void main(String[] args) throws InterruptedException {
People people1 = new People();
People people2 = new People();
new Thread(()->{people1.live();},"a").start();
TimeUnit.SECONDS.sleep(1);
new Thread(()->{people2.dead();},"b").start();
}
}
class People{
public synchronized void live() {
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("活着");
}
public synchronized void dead(){
System.out.println("死亡");
}
}
问题四结果如下:
原因: 因为Synchronized锁(同步代码块),锁住了上面的people 对象但是,两个锁锁住的是不同的对象,所以b线程不会等待a线程的所释放在运行,所以b会直接运行。
运行结果如图
问题五:两个静态的锁方法,new一个对象调用,在live方法中睡3秒,执行结果是什么
代码如下:
package com.mao.lock8;
import java.util.concurrent.TimeUnit;
/**
* author 小毛桑
*
* @date 2021/10/21 0021 12:34
* 问题五:两个静态的锁方法,new一个对象调用,在live方法中睡3秒,执行结果是什么
*/
public class lock5 {
public static void main(String[] args) {
People people = new People();
new Thread(()->{people.live();},"a").start();
new Thread(()->{people.dead();},"b").start();
}
}
class People{
public static synchronized void live() {
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("活着");
}
public static synchronized void dead(){
System.out.println("死亡");
}
}
问题四结果如下:
原因: 因为Synchronized锁(同步代码块),因为static 所以锁住People这个类。
运行结果如图
问题六:两个静态的锁方法,new两个对象分别调用,在live方法中睡3秒,执行结果是什么
代码如下
package com.mao.lock8;
import java.util.concurrent.TimeUnit;
/**
* author 小毛桑
*
* @date 2021/10/21 0021 12:38
* 问题六:两个静态的锁方法,new两个对象分别调用,在live方法中睡3秒,执行结果是什么
*/
public class lock6 {
public static void main(String[] args) {
People people1 = new People();
People people2 = new People();
new Thread(()->{people1.live();},"a").start();
new Thread(()->{people2.dead();},"b").start();
}
}
class People{
public static synchronized void live() {
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("活着");
}
public static synchronized void dead(){
System.out.println("死亡");
}
}
运行结果如图:
问题七:一个静态的锁方法,一个普通锁方法,new一个对象调用,在live方法中睡3秒,执行结果是什么
代码如下
package com.mao.lock8;
import java.util.concurrent.TimeUnit;
/**
* author 小毛桑
*
* @date 2021/10/21 0021 12:42
* 问题七:一个静态的锁方法,一个普通锁方法,new一个对象调用,在live方法中睡3秒,执行结果是什么
*/
public class lock7 {
public static void main(String[] args) {
People people = new People();
new Thread(()->{people.live();},"a").start();
new Thread(()->{people.dead();},"b").start();
}
}
class People{
public static synchronized void live(){
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("活着");
}
public synchronized void dead(){
System.out.println("死亡");
}
}
同样只要确认锁的是不是一个东西就知道会不会阻塞,调用live时阻塞的是People.class,调用 dead 时阻塞的是people对象
运行结果:
问题八:一个静态的锁方法,一个普通锁方法,new两个对象分别调用,在live方法中睡3秒,执行结果是什么
package com.mao.lock8;
import java.util.concurrent.TimeUnit;
/**
* author 小毛桑
*
* @date 2021/10/21 0021 12:51
* 问题八:一个静态的锁方法,一个普通锁方法,new两个对象分别调用,在live方法中睡3秒,执行结果是什么
*/
public class lockEight {
public static void main(String[] args) {
People people1 = new People();
People people2 = new People();
new Thread(()->{people1.live();},"a").start();
new Thread(()->{people2.dead();},"b").start();
}
}
class People{
public static synchronized void live(){
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("活着");
}
public synchronized void dead(){
System.out.println("死亡");
}
}
运行结果如下:
调用live时阻塞的是People.class,调用dead时阻塞的是people2
学习的视频链接
…