标签:过多 进程 主题 静态代理 运行 struct 打印 ide write
程序-----(运行)------>进程---------->线程
线程是独立的执行路径
程序运行时,即使自己没有创建线程,后台也会有多个线程---主线程,gc线程
一个进程中,如果开辟多个线程,线程的调度由调度器安排调度,而调度去与系统相关,人为无法干预
对同一份资源,操作时,会存在资源抢夺的问题,需要加入并发控制
线程会带来额外开销,如CPU调度时间,并发控制开销
每个线程只在自己的工作内存交互,互不干预
自定义线程类继承Tread类
重写run()方法,编写线程执行体
创建线程对象,调用start()方法其拆散多线程
//继承Thread类
public class TestThread1 extends Thread {
//run方法——TestTread1线程
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println("这是Testread1线程"+i);
}
}
//main方法——主线程
public static void main(String[] args) {
TestThread1 testThread1 = new TestThread1();//创建线程
testThread1.start();//开启多线程
for (int i = 0; i < 1000; i++) {
System.out.println("这是主线程"+i);
}
}
}
线程开启不一定立即执行,由CPU调度执行,人为无法干预
testThread1.start()开启多线程后,线程时交替执行的
而testThread1.run()是调用TestThread1类中的run()方法,顺序执行,因此run执行完后才执行main
public class TestThread1 extends Thread {
//run方法——TestTread1线程
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println("这是Testread1线程"+i);
}
}
//main方法——主线程
public static void main(String[] args) {
TestThread1 testThread1 = new TestThread1();
testThread1.run();//调用run方法
for (int i = 0; i < 1000; i++) {
System.out.println("这是主线程"+i);
}
}
}
用多线程下载架包
将commons-io 2.6拷仅idea的lib目录
右键add as library
//练习Thread,实现多线程同步下载图片
public class TestThread2 extends Thread{
private String url;//网络图片地址
private String name;//保存的文件名
public TestThread2(String url, String name) {
this.url = url;
this.name = name;
}
@Override
public void run() {
WebDownloader webDownloader = new WebDownloader();
webDownloader.downloader(url,name);
System.out.println("下载文件名为:"+name);
}
public static void main(String[] args) {
TestThread2 t1 = new TestThread2("https://04imgmini.eastday.com/mobile/20201124/20201124125422_b97573c574f48a6af5f5c5c9a9beea1b_1.jpeg","aaa1.jpg");
TestThread2 t2 = new TestThread2("https://04imgmini.eastday.com/mobile/20201124/20201124125422_b97573c574f48a6af5f5c5c9a9beea1b_2.jpeg","aaa2.jpg");
TestThread2 t3 = new TestThread2("https://04imgmini.eastday.com/mobile/20201124/20201124125422_b97573c574f48a6af5f5c5c9a9beea1b_3.jpeg","aaa3.jpg");
t1.start();
t2.start();
t3.start();
}
}
下载的顺序不是按t1,t2,t3,开启多线程后而是由系统自动调度分配
定义MYRunnable类实现Runable接口
实现run()方法,编写线程执行体
创建线程对象,调用start()方法启动线程
public class TestThread3 implements Runnable{
//重现run方法
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("这是子线程"+i);
}
}
public static void main(String[] args) {
//创建runnable接口的实现对象
TestThread3 testThread3 = new TestThread3()
//创建线程对象——代理
Thread thread = new Thread(testThread3);
//开启线程
thread.start();
for (int i = 0; i < 1000; i++) {
System.out.println("主线程"+i);
}
}
}
线程不安全
public class TestThread4 implements Runnable{
private int ticketNum = 10;
@Override
public void run() {
while (true) {
if (ticketNum <=0){
break;
}
//延迟
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
//Thread.currentThread().getName()获取姓名
System.out.println(Thread.currentThread().getName()+"抢到了第"+ (ticketNum--)+"张票");
}
}
public static void main(String[] args) {
TestThread4 ticket = new TestThread4();
new Thread(ticket,"小明").start();
new Thread(ticket,"小红").start();
new Thread(ticket,"黄牛").start();
}
}
//龟兔赛跑
public class TestThread5 implements Runnable {
private static String winner;//胜利者
private final int LENGTH = 1000;//赛道长度
//设置赛道
@Override
public void run() {
for (int i = 0; i <= LENGTH; i++) {
//判断比赛是否结束
boolean flag = this.gameover(i);
//如果结束,退出循环
if (flag){
break;
}
//比赛进度
System.out.println(Thread.currentThread().getName()+"跑了"+i+"步");
//模拟兔子的状态
if (Thread.currentThread().getName().equals("兔子")) {//不能用 == "兔子"
//模拟兔子跑步比乌龟快
i += 49;
//模拟兔子休息
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
//判断比赛是否结束方法
private boolean gameover(int steps) {
//已经有胜利者了,返回true
if (winner != null) {
return true;
} else if (steps>=LENGTH){
winner = Thread.currentThread().getName();
System.out.println(winner+"赢得了比赛");
return true;
}
//无胜利者,返回false
return false;
}
//主线程
public static void main(String[] args) {
TestThread5 race = new TestThread5();
new Thread(race, "兔子").start();
new Thread(race, "乌龟").start();
}
}
实现Callable接口,需要返回值类型
重现call方法,需要抛出异常
创建目标对象
创建执行服务
提交执行
获取结果
关闭服务
public class TestCallable implements Callable{
private String url;
private String name;
public TestCallable(String url, String name) {
this.url = url;
this.name = name;
}
//重写call方法
@Override
public Boolean call() throws Exception {
this.download(url,name);
System.out.println("下载文件名为:"+name);
return true;
}
//下载方法
public void download(String url, String name) {
try {
FileUtils.copyURLToFile(new URL(url),new File(name));
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
TestCallable t1 = new TestCallable("https://04imgmini.eastday.com/mobile/20201124/20201124125422_b97573c574f48a6af5f5c5c9a9beea1b_1.jpeg","bbb1.jpg");
TestCallable t2 = new TestCallable("https://04imgmini.eastday.com/mobile/20201124/20201124125422_b97573c574f48a6af5f5c5c9a9beea1b_2.jpeg","bbb2.jpg");
TestCallable t3 = new TestCallable("https://04imgmini.eastday.com/mobile/20201124/20201124125422_b97573c574f48a6af5f5c5c9a9beea1b_3.jpeg","bbb3.jpg");
//创建执行服务
ExecutorService ser = Executors.newFixedThreadPool(3);
//提交执行
Future<Boolean> submit1 = ser.submit(t1);
Future<Boolean> submit2 = ser.submit(t2);
Future<Boolean> submit3 = ser.submit(t3);
//获取结果
Boolean rs1 = submit1.get();
Boolean rs2 = submit2.get();
Boolean rs3 = submit3.get();
System.out.println("bbb1.jpg is "+rs1);//可以打印返回值
System.out.println("bbb2.jpg is "+rs2);
System.out.println("bbb3.jpg is "+rs3);
//关闭服务
ser.shutdownNow();
}
}
一个接口只有唯一的一个抽象方法
由于这个接口中只有这个方法,因此相比匿名内部类,可以实现除了类名,连方法名都可以 省略
public interface Runnable{
public abstruct run();
}
推导lamda表达式(逐步简化)
关于内部类
public class TestLambda {
//成员内部类
class Like2 implements ILike {
@Override
public void show() {
System.out.println("接口实现方式——成员内部类");
}
}
//静态内部类
static class Like3 implements ILike {
@Override
public void show() {
System.out.println("接口实现方式——静态内部类");
}
}
public static void main(String[] args) {
//1.正常操作 —— 在外部写接口的实现类
new Like1().show();
//2. 成员内部类 —— 将实现类写到内部
TestLambda testLambda = new TestLambda();
testLambda.new Like2().show();
//3. 静态内部类
new Like3().show();
//4. 局部内部类
class Like4 implements ILike {
@Override
public void show() {
System.out.println("接口实现方式——局部内部类");
}
}
new Like4().show();
//5. 匿名内部类
new ILike() {
@Override
public void show() {
System.out.println("接口实现方式——匿名内部类");
}
}.show();
//6. lambda简化
ILike like = ()->{
System.out.println("接口的实现方式——lambda表达式");
};
like.show();
}
}
//定义一个函数式接口
interface ILike {
void show();
}
//接口实现类
class Like1 implements ILike {
@Override
public void show() {
System.out.println("接口实现方式——写实现类(外部)");
}
}
示例2
public class TestLambda2 {
public static void main(String[] args) {
//匿名内部类
new Meals() {
@Override
public void show(String name, String food, int nums) {
System.out.println(name+"吃了"+nums+"份"+food);
}
}.show("早餐","面包",3);
//lambda表达式
Meals meals;
meals = (a,b,c)->{
System.out.println(a+"吃了"+c+"份"+b);
};
meals.show("早餐","面包",3);
//简化lambda表达式
meals = (a,b,c) -> System.out.println(a+"吃了"+c+"份"+b);
meals.show("早餐","面包",3);
}
}
interface Meals{
void show(String name, String food, int nums);
}
如果方法重载了还满足lambda只有一个方法的要求吗?
不行
真实对象和代理对象都要实现同一个接口
代理对象要代理真实角色
不改变原有代码,去实现新的功能
- 静态代理模式——对方法的增强
- 装饰器模式——对对象的增强
代理对象可以做很多真实对象做不了的事
真实对象专注做自己的事
public class StaticProxy {
public static void main(String[] args) {
People you = new People();
new WeddingCompany(you);
}
}
interface Merry{
void merry();
}
//你——真实对象
class People implements Merry{
@Override
public void merry() {
System.out.println("我终于结婚了,超开心TAT");
}
}
//婚庆公司——代理
class WeddingCompany implements Merry{
private Merry customer;
public WeddingCompany(Merry customer) {
this.customer = customer;
this.merry();
}
@Override
public void merry() {
berfore();
customer.merry();
after();
}
private void berfore() {
System.out.println("结婚前,布置婚礼");
}
private void after() {
System.out.println("结婚后,收取尾款");
}
}
/*
结婚前,布置婚礼
我终于结婚了,超开心TAT
结婚后,收取尾款
*/
与多线程创建类比
//静态代理模式
new WeddingCompany(new People()).merry();
//线程创建也构成静态代理的要求
new Thread( ()->System.out.println("love")).start();
真实对象和代理对象都要实现同一个接口
Thread 实现 Runnable接口
lambda表达式为一个匿名的实现类也是实现 Runnable接口
代理对象要代理真实角色
Thread真实代理lambda表达式的匿名类
?
public class TestStop implements Runnable{
boolean flag = true;
@Override
public void run() {
//子线程就两条语句,当while执行完,子线程就结束了,但while(true)为无限循环,也就是说子线程只有在flag变为false的时候才会停止
int i = 0;
while (flag) {
System.out.println("*****************子线程跑了"+i++);
}
}
//停止线程
void stop() {
flag = false;
System.out.println("**************子线程停止了");
}
public static void main(String[] args) {
TestStop tt = new TestStop();
new Thread(tt).start();
for (int i = 0; i < 1000; i++) {
System.out.println("主线程跑了"+i);
//主线程跑到800的时候把flag变为false——停止子线程
if (i==800) {
tt.stop();
}
}
}
}
模拟网络延迟——放大问题的发生行
public class TestThread4 implements Runnable{
private int ticketNum = 10;
@Override
public void run() {
while (true) {
if (ticketNum <=0){
break;
}
try {
//模拟网络延迟——放大问题的发生行,可能打印负数,这个线程本身是不安全的
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"抢到了第"+ (ticketNum--)+"张票");
}
}
public static void main(String[] args) {
TestThread4 ticket = new TestThread4();
new Thread(ticket,"小明").start();
new Thread(ticket,"小红").start();
new Thread(ticket,"黄牛").start();
}
}
倒计时
//倒计时
public class TestSleep {
public static void main(String[] args) {
for (int i = 10; i > 0; i--) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(i);
}
}
}
/*
10
9
8
...
1
*/
系统时间
public class TestSleep2 {
public static void main(String[] args) {
//系统时间
Date date;
while (true) {
try {
date = new Date(System.currentTimeMillis());
Thread.sleep(1000);
System.out.println(new SimpleDateFormat("HH:mm:ss").format(date));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
/*
21:32:09
21:32:10
21:32:11
21:32:12
...
*/
public class TestYield {
public static void main(String[] args) {
new Thread(new ThreadYield(),"线程1").start();
new Thread(new ThreadYield(),"线程2").start();
}
}
class ThreadYield implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"运行中");
Thread.yield();
System.out.println(Thread.currentThread().getName()+"已结束");
}
}
/*
线程1运行中
线程2运行中
线程2已结束
线程1已结束
*/
合并线程,待此线程执行完后,再执行其他线程,其他线程阻塞
可以想象成插队
public class TestJoin {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
System.out.println("子线程join后就是vip线程了"+i);
}
});
t1.start();
for (int i = 0; i < 500; i++) {
System.out.println("这是main线程"+i);
if (i==400) {
t1.join();
}
}
}
}
开始时,两个线程交替进行,
但到主线程i=400开始,子线程的优先级变高,主线程开始等待,子线程执行完后才开始执行主线程
getState()
新生 new
就绪
运行 Runnable
死亡 Dead
public class TestState{
//观察子线程
public static void main(String[] args) {
//1.新生 2.就绪
Thread t1 = new Thread(()->{
try {
//4.阻塞
Thread.sleep(1000);
} catch (InterruptedExc eption e) {
e.printStackTrace();
}
//5.执行完这句话--->死亡
System.out.println("lsat sentence");
});
System.out.println(t1.getState());//观察状态
//3.启动
t1.start();
System.out.println(t1.getState());
//启动之后
while (t1.getState() != Thread.State.TERMINATED) {
//只要子线程不终止,在主线程中就不停检测子线程状态
try {
Thread.sleep(100);
System.out.println(t1.getState());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
getPriority()
setPriority(int x)
public static void main(String[] args) {
//查看主线程优先级
System.out.println(Thread.currentThread().getName() + "优先级为" + Thread.currentThread().getPriority());
//创建线程
Thread t1 = new Thread(() -> System.out.println(Thread.currentThread().getName() + "优先级为" + Thread.currentThread().getPriority()));
Thread t2 = new Thread(() -> System.out.println(Thread.currentThread().getName() + "优先级为" + Thread.currentThread().getPriority()));
Thread t3 = new Thread(() -> System.out.println(Thread.currentThread().getName() + "优先级为" + Thread.currentThread().getPriority()));
Thread t4 = new Thread(() -> System.out.println(Thread.currentThread().getName() + "优先级为" + Thread.currentThread().getPriority()));
//设置优先级
t1.setPriority(7);
t2.setPriority(3);
t3.setPriority(Thread.MAX_PRIORITY);
t4.setPriority(1);
//启动线程
t1.start();
t2.start();
t3.start();
t4.start();
}
}
/*
main优先级为5
Thread-2优先级为10
Thread-0优先级为6
Thread-1优先级为3
Thread-3优先级为1
*/
性能倒置
多跑几次,输出结果也可能是这样,因为设置优先级并不代表一定优先执行,而是优先执行的概率大,(和yield()一样,重新调度线程)具体还是看CPU调度,人为无法干预
/*
main优先级为5
Thread-0优先级为6
Thread-2优先级为10
Thread-1优先级为3
Thread-3优先级为1
*/
线程分为用户线程和守护线程
虚拟机必须确保用户线程执行完毕
虚拟机不用等待守护线程执行完毕
public class TestDeamon {
public static void main(String[] args) {
//线程1——输出五秒系统时间
new Thread(()->{
for (int i = 0; i < 5; i++) {
Date date = new Date(System.currentTimeMillis());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
System.out.println(sdf.format(date));
}
System.out.println("==Goodbye==");
}).start();
//线程2——守护线程
Thread t2 = new Thread(() -> {
while (true) {
System.out.println("==守护线程==");
}
});
t2.setDaemon(true);//线程默认false,true后变为守护线程
t2.start();
}
}
/*
==守护线程==
==守护线程==
15:46:49
==Goodbye==
==守护线程==
==守护线程==
==守护线程==
*/
线程2为while死循环,但线程1执行完,程序依旧结束了,因为虚拟机不用等待守护线程执行完毕
多个线程访问同一个对象的问题——并发问题
解决线程的安全性
锁提高安全性的同时,也会降低性能
买票案例
public class Ticket {
public static void main(String[] args) {
TicketSale station = new TicketSale();
new Thread(station, "小明").start();
new Thread(station, "小红").start();
new Thread(station, "黄牛").start();
}
}
class TicketSale implements Runnable{
private int ticketNums = 10;
private boolean flag = true;
@Override
public void run() {
//买票
while (flag) {
if (ticketNums<=0){
flag = false;
return;//到0就退出循环,不执行buyTicket();
}
buyTicket();
/*
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
*/
}
}
//购票方法
private void buyTicket (){
System.out.println(Thread.currentThread().getName()+"抢到了第"+(ticketNums--)+"张票");
}
}
/*
小明抢到了第10张票
黄牛抢到了第8张票
小红抢到了第9张票
小明抢到了第6张票
黄牛抢到了第7张票
小明抢到了第4张票
小红抢到了第5张票
小明抢到了第2张票
黄牛抢到了第3张票
小红抢到了第1张票...*/
这个sleep放buy方法里,会导致第一个线程在run里不断调用buy,直接买完所有的票
放buy外面,sleep阻塞,下一个线程就有机会买到了
用sleep方法,放大问题的发生性
/* 黄牛抢到了第10张票 小明抢到了第9张票 小红抢到了第10张票 小红抢到了第8张票 小明抢到了第7张票 黄牛抢到了第6张票...*/
可以看见,黄牛,小红都抢到了第10张票——即表明线程不安全
银行取钱
public class BankTest {
public static void main(String[] args) {
System.out.println("=======小明夫妻共有5000元存款=======");
Account account = new Account("存款", 5000);
new Thread(new Drawing(account, 100), "小明").start();
new Thread(new Drawing(account, 5000), "妻子").start();
}
}
//账户
class Account{
private String name;//账户名
private int money;//存款
public Account(String name,int money) {
this.name = name;
this.money = money;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getMoney() {
return money;
}
public void setMoney(int money) {
this.money = money;
}
}
//银行取款
class Drawing implements Runnable {
Account account;//账户
int withdraw;//取现
int cash;//现金
public Drawing(Account account, int withdraw) {
this.account = account;
this.withdraw = withdraw;
}
@Override
public void run() {
//如果没有钱退出
if (account.getMoney() - withdraw <0) {
System.out.println("存款只有"+account.getMoney()+"取不了"+ withdraw +"元");
return;
}
//sleep放大问题的发生性
//小明和妻子两个线程都在这等待1秒
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
account.setMoney(account.getMoney() - withdraw); //卡内余额
cash += withdraw;//现金
System.out.println(Thread.currentThread().getName()+"取走了"+withdraw+"元");
System.out.println(account.getName()+"余额为"+account.getMoney()+"元");
System.out.println(Thread.currentThread().getName()+"手中的钱"+cash+"元");
}
}
/*
=======小明夫妻共有5000元存款=======
妻子取走了5000元
存款余额为0元
妻子手中的钱5000元
小明取走了100元
存款余额为-100元
小明手中的钱100元
*/
取钱前,小明和妻子等待了1秒,同时操作1个对象,因此都能取出钱
list案例
public class ListTest {
public static void main(String[] args) {
List list = new ArrayList<>();
for (int i = 0; i < 100000; i++) {
new Thread(()->{
list.add(Thread.currentThread().getName());
}).start();
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(list.size());
}
}
//99973
99973而不是预想的100000,等待了100ms,同时添加1个对象,数据覆盖,因此线程也是不安全的
对属性的保护——private,写set/get方法
实现原理:队列与锁
但也有弊端
不是对象所有内容都需要同步的
修改部分需要同步,而只读部分不需要同步,浪费资源
买票案例
private synchronized void buyTicket (){
System.out.println(Thread.currentThread().getName()+"抢到了第"+(ticketNums--)+"张票");
}
}
/*
小明抢到了第10张票
小红抢到了第9张票
黄牛抢到了第8张票
小红抢到了第7张票
小明抢到了第6张票
黄牛抢到了第5张票
小红抢到了第4张票
小明抢到了第3张票
黄牛抢到了第2张票
小红抢到了第1张票
*/
银行案例
@Override
public void run() {
synchronized (account) {
//如果没有钱退出
if (account.getMoney() - withdraw <0) {
System.out.println("存款只有"+account.getMoney()+"取不了"+ withdraw +"元");
return;
}
//sleep放大问题的发生性
//小明和妻子两个线程都在这等待1秒
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
account.setMoney(account.getMoney() - withdraw); //卡内余额
cash += withdraw;//现金
System.out.println(Thread.currentThread().getName()+"取走了"+withdraw+"元");
System.out.println(account.getName()+"余额为"+account.getMoney()+"元");
System.out.println(Thread.currentThread().getName()+"手中的钱"+cash+"元");
}
}
/*
=======小明夫妻共有5000元存款=======
小明取走了100元
存款余额为4900元
小明手中的钱100元
存款只有4900取不了5000元
*/
list案例
for (int i = 0; i < 100000; i++) {
new Thread(() -> {
synchronized (list) {
list.add(Thread.currentThread().getName());
}
}).start();
}
//100000
JUC
public class TestJUC {
public static void main(String[] args) {
//安全类型的集合
CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<String>();
for (int i = 0; i < 10000; i++) {
new Thread(()-> list.add(Thread.currentThread().getName())).start();
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(list.size());
}
}
//10000
transient——临时的
volatile——不可被序列化
public class DeadLock {
public static void main(String[] args) {
System.out.println("0=口红,1=镜子");
new MyMakeup("小明",0).start();
new MyMakeup("小红",1).start();
}
}
class Mirror {}
class Lipstick {}
class MyMakeup extends Thread {
//资源
static Mirror mirror = new Mirror();
static Lipstick lipstick = new Lipstick();
//人物、选择
String name;
int choice;
public MyMakeup(String name, int choice) {
super(name);
this.choice = choice;
}
@Override
public void run() {
//化妆
makeup();
}
//化妆,互相持有对方的锁——需要拿到对方的资源
private void makeup() {
name = Thread.currentThread().getName();
if (choice==0) {
//获得口红
synchronized (lipstick){
System.out.println(name+"拿到了口红");
//使用了1秒
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//获得镜子
synchronized (mirror) {
System.out.println(name+"拿到了镜子");
}
}
} else {
//获得镜子
synchronized (mirror) {
System.out.println(name+"拿到了镜子");
////使用了1秒
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//获得口红
synchronized (lipstick) {
System.out.println(name+"拿到了口红");
}
}
}
}
}
/*
0=口红,1=镜子
小明拿到了口红
小红拿到了镜子
*/
小明先拿到口红,小红先拿到镜子
但都卡住了,拿不到另一样东西
小明锁了口红时,要拿镜子这个资源,但镜子被小红锁了,要等待小红执行完解锁
小红锁了镜子时,要拿口红这个资源,但口红被小明锁了,要等待小明执行完解锁,这样就死锁了
private void makeup() {
name = Thread.currentThread().getName();
if (choice==0) {
//获得口红
synchronized (lipstick){
System.out.println(name+"拿到了口红");
//使用了1秒
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(name+"放回了口红");
}
//获得镜子
synchronized (mirror) {
System.out.println(name+"拿到了镜子");
}
} else {
//获得镜子
synchronized (mirror) {
System.out.println(name+"拿到了镜子");
////使用了1秒
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(name+"放回了镜子");
}
//获得口红
synchronized (lipstick) {
System.out.println(name+"拿到了口红");
}
}
}
/*
0=口红,1=镜子
小红拿到了镜子
小明拿到了口红
小明放回了口红
小明拿到了镜子
小红放回了镜子
小红拿到了口红
*/
ReentrantLock类——可重入锁
public class TestLock {
public static void main(String[] args) {
Test test = new Test();
new Thread(test,"线程1").start();
new Thread(test,"线程2").start();
new Thread(test,"线程3").start();
}
}
class Test implements Runnable {
ReentrantLock lock = new ReentrantLock();//定义Lock锁
int num = 10;
@Override
public void run() {
while(true) {
try {
lock.lock();//加锁
if (num>0) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" :"+num--);
} else {
break;
}
} finally {
lock.unlock();//解锁
}
}
}
}
这是lock锁this这个对象,但如果要像Synchronized(特定对象),又该如何用lock实现?
生产者消费者问题
public class Demo02 {
public static void main(String[] args) {
Buffer buffer = new Buffer();//缓冲区
new Productor(buffer).start(); //生产者
new Consumer(buffer).start(); //消费者
}
}
//产品
class Product {
int id;
public Product(int id) {
this.id = id;
}
}
//缓冲区
class Buffer {
//1. 定义一个容器——用于存放产品
Product[] container = new Product[10];//可以存10个
int count = 0;//产品个数
//2. 生产者把东西放到缓冲区的方法
synchronized int push (Product product) {
//如果容器满了,就通知生产者停止生产
if (count>= container.length) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//如果容器没满,生产者一直会生产
//将生产的产品存入缓冲区
container[count++] = product;
//通知消费者消费
this.notifyAll();
return count;
}
//3. 消费者把东西从到缓冲区取出的方法
synchronized Product pop() {
//如果容器空了,通知消费者等待
if (count <= 0) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//如果容器没满,通知消费者消费
//将产品从缓冲区取出
Product takeout = container[--count];
System.out.println(" ===取出"+takeout.id+"号===");
//通知生产者生产
this.notifyAll();
return takeout;
}
}
//生产者
class Productor extends Thread{
Buffer buffer;
public Productor(Buffer buffer) {
this.buffer = buffer;
}
@Override
public void run() {
int id = 1;
while(true) {
//生产、把产品放到缓冲区
Product product = new Product(id);
System.out.println("生产了"+id+"号产品\n"+"===投放"+(id++)+"号===\n===仓库共有"+buffer.push(product)+"件产品==========");
if (id>=100) {
break;
}
}
}
}
//消费者
class Consumer extends Thread{
Buffer buffer;
public Consumer(Buffer buffer) {
this.buffer = buffer;
}
@Override
public void run() {
int count = 1;
while(true){
//这里buffer.pop()返回的是一个product对象所有能用.id
System.out.println(" "+buffer.pop().id+"号完成消费");
if (count>=100) {
return;
}
}
}
}
输出日志
生产了1号产品
===投放1号===
===仓库共有1件产品==========
生产了2号产品
===投放2号===
===仓库共有2件产品==========
生产了3号产品
===投放3号===
===仓库共有3件产品==========
生产了4号产品
===投放4号===
===仓库共有4件产品==========
生产了5号产品
===投放5号===
===仓库共有5件产品==========
生产了6号产品
===投放6号===
===仓库共有6件产品==========
生产了7号产品
===投放7号===
===仓库共有7件产品==========
生产了8号产品
===投放8号===
===仓库共有8件产品==========
生产了9号产品
===投放9号===
===仓库共有9件产品==========
生产了10号产品
===投放10号===
===仓库共有10件产品==========
===取出10号===
10号完成消费
生产了11号产品
===投放11号===
===仓库共有10件产品==========
===取出11号===
11号完成消费
===取出12号===
12号完成消费
===取出9号===
9号完成消费
===取出8号===
8号完成消费
===取出7号===
7号完成消费
===取出6号===
6号完成消费
===取出5号===
5号完成消费
===取出4号===
4号完成消费
===取出3号===
3号完成消费
===取出2号===
2号完成消费
===取出1号===
1号完成消费
生产了12号产品
===投放12号===
===仓库共有10件产品==========
生产了13号产品
===投放13号===
===仓库共有1件产品==========
生产了14号产品
===投放14号===
===仓库共有2件产品==========
===取出14号===
14号完成消费
===取出13号===
13号完成消费
生产了15号产品
===投放15号===
===仓库共有1件产品==========
......
关于wait
//信号灯法
public class Demo03 {
public static void main(String[] args) {
TvShow tvShow = new TvShow();
new Actors(tvShow).start();
new Audiences(tvShow).start();
}
}
//演员——生产者
class Actors extends Thread {
TvShow tvShow;
public Actors(TvShow tvShow) {
super("演员");
this.tvShow = tvShow;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
if (i%2==0) {
tvShow.transcribe("快乐大本营");
} else {
tvShow.transcribe("抖音");
}
}
}
}
//观众——消费者
class Audiences extends Thread {
TvShow tvShow;
public Audiences(TvShow tvShow) {
super("观众");
this.tvShow = tvShow;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
if (i%2==0) {
tvShow.watch("快乐大本营");
} else {
tvShow.watch("抖音");
}
}
}
}
//节目——产品————由于只两种种状态,所以不需要缓冲区
class TvShow {
boolean flag = true;
String programName;
//演员录制,观众等待
synchronized void transcribe (String programName){
//false通知演员休息
if (!flag) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//true通知演员表演
System.out.println(Thread.currentThread().getName()+"录制了"+programName);
this.notifyAll();//演员表演完,通知等待的观众再观看
flag = !flag;
}
//观众观看,演员休息
synchronized void watch(String programName) {
//ture通知观众等待
if (flag) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//false通知观众收看
System.out.println(Thread.currentThread().getName()+"收看了"+programName);
this.notifyAll();//观众受看完,通知休息的演员再录制
flag = !flag;
}
}
public class executorService {
public static void main(String[] args) {
//开启线程池
ExecutorService service = Executors.newFixedThreadPool(10);
service.execute(new Test());//execute(),提交runnable实现的线程
service.execute(new Test());
service.execute(new Test());
service.execute(new Test());
service.submit(new Test());//通用的提交线程方法
service.submit(new Test());
service.submit(new Test());
//关闭线程池
service.shutdown();
}
}
class Test implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"helloworld");
}
}
public class Demo01 {
public static void main(String[] args) {
//Thread
new Thread1().start();
//Runnable
new Thread(new Thread2()).start();
//Callable
FutureTask<Integer> futureTask = new FutureTask<Integer>(new Thread3());
new Thread(futureTask);//futrueTask继承了Runnable接口
//线程池
ExecutorService service = Executors.newFixedThreadPool(3);
service.submit(new Thread1());//提交
service.submit(new Thread2());
service.submit(new Thread3());
service.shutdown();//关闭线程池
}
}
class Thread1 extends Thread {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"Thread实现多线程");
}
}
class Thread2 implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"Runnable实现多线程");
}
}
class Thread3 implements Callable<Integer> {
@Override
public Integer call() throws Exception {
System.out.println(Thread.currentThread().getName()+"Callable实现多线程");
return 100;
}
}
标签:过多 进程 主题 静态代理 运行 struct 打印 ide write
原文地址:https://www.cnblogs.com/Sheltonz/p/14070779.html