好文推荐:排序、查找算法齐全(程序员必会 好文 值得收藏!)
多线程,简单的来说,就是多任务。
方法间调用:普通方法调用,从哪里来到哪里去,闭合的一条路径。
多线程使用: 开辟了多条路径。
创建线程三种方式:
你知道三高问题是哪三高吗?
高可用、高性能、高并发
代码敲一敲,你就知道啦。
public class Test1 extends Thread {
//创建接入口
@Override
public void run() {
for(int i=0;i<20;i++) {
System.out.println("敲代码");
}
}
public static void main(String[] args) {
/*
* 创建线程方式一:
* 继承Thread+重写run
*/
//创建子类对象
Test1 st=new Test1();
//启动
st.start(); //不保证立即运行,cpu调用
// st.run(); //方法调用
for(int i=0;i<20;i++) {
System.out.println("学习中");
}
}
}
知道利用多线程实现网上图片的下载,也是必备的小技巧!
/*
* 下载图片
*/
public class Test2 {
public void download(String url,String name) {
try {
FileUtils.copyURLToFile(new URL(url),new File(name));
} catch (MalformedURLException e) {
e.printStackTrace();
System.out.println("不合法的url!");
} catch (IOException e) {
e.printStackTrace();
System.out.println("下载失败!");
}
}
}
public class TDownloader extends Thread {
private String url; //远程路径
private String name; //存储路径
public TDownloader(String url, String name) {
this.url = url;
this.name = name;
}
@Override
public void run() {
Test2 wd=new Test2();
wd.download(url,name);
System.out.println(name);
}
public static void main(String[] args) {
TDownloader td1=new TDownloader("图片网址","p1.jpg");
TDownloader td2=new TDownloader("图片网址","p2.jpg");
TDownloader td3=new TDownloader("图片网址","p3.jpg");
//启动三个线程
td1.start();
td2.start();
td3.start();
}
}
学了就去试试吧
看到实现,你应该想到啥?
没错,就是接口!
/*
* 实现Runnable
*/
public class Test3 implements Runnable {
/*
* 线程接入点
*/
@Override
public void run() {
for(int i=0;i<20;i++) {
System.out.println("敲代码");
}
}
public static void main(String[] args) {
new Thread(new Test3()).start();
for(int i=0;i<20;i++) {
System.out.println("听歌中");
}
}
}
学习了多线程,不拿来展示它的作用也是没得用的,此次就以大家最熟悉的龟兔赛跑和抢票问题来实现吧。
public class Test4 implements Runnable{
//票数
private int tickets=99;
@Override
public void run() {
while(true) {
if(tickets<0) {
break;
}
System.out.println(Thread.currentThread().getName()+"-->"+tickets--);
}
}
public static void main(String[] args) {
//一份资源
Test4 web1=new Test4();
//多个代理
new Thread(web1,"程序员").start();
new Thread(web1,"码农").start();
new Thread(web1,"开发工程师").start();
}
}
/*
* 模拟龟兔赛跑
*/
public class Test5 implements Runnable{
private static String winner; //胜利者
@Override
public void run() {
for(int steps=1;steps<=100;steps++) {
//模拟休息
if(Thread.currentThread().getName().equals("rabbbit")&&steps%100==0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+"-->"+steps);
//比赛是否结束
boolean flag=gameOver(steps);
if(flag) {
break;
}
}
}
private boolean gameOver(int steps) {
if(winner!=null) { //存在胜利者
return true;
}else {
if(steps==100) {
winner=Thread.currentThread().getName();
System.out.println("winner ==>"+winner);
return true;
}
}
return false;
}
public static void main(String[] args) {
Test5 racer=new Test5();
new Thread(racer,"tortoise").start();
new Thread(racer,"rabbit").start();
}
}
实现Callable步骤:
/*
* 静态代理:
* 接口:
* 1、真实角色
* 2、代理角色
*/
public class Test6 {
public static void main(String[] args) {
new WeddingCompany(new You()).happy();
//new Thread(线程对象).start()
}
}
interface Marry{
void happy();
}
class You implements Marry{
@Override
public void happy() {
System.out.println("You and ");
}
}
//代理角色
class WeddingCompany implements Marry{
//真实角色
private Marry target;
public WeddingCompany(Marry target) {
this.target=target;
}
@Override
public void happy() {
ready();
this.target.happy();
after();
}
private void ready() {
System.out.println("布置");
}
private void after() {
System.out.println("开始");
}
}
public class TestLambda {
//静态内部类
static class Test implements Runnable{
public void run() {
for(int i=0;i<20;i++) {
System.out.println("敲代码");
}
}
}
public static void main(String[] args) {
//静态内部类
// new Thread(new Test()).start();
//局部内部类
class Test2 implements Runnable{
public void run() {
for(int i=0;i<20;i++) {
System.out.println("敲代码");
}
}
}
//局部内部类
// new Thread(new Test2()).start();
//匿名内部类
new Thread(new Runnable() {
public void run() {
for(int i=0;i<20;i++) {
System.out.println("敲代码");
}
}
}).start();
//jdk8简化 lambda 用于简化简单的线程 只能推导一个方法
new Thread(()->{
for(int i=0;i<20;i++) {
System.out.println("敲代码");
}
}).start();
}
}
温馨提示: lambda :可以带参数,一句的可以省写花括号,类型名(多个参数也行)也可省写
public class Test7 implements Runnable{
//加入标志 标记线层体是否可以运行
private boolean flag=true;
private String name;
public Test7(String name) {
this.name=name;
}
@Override
public void run() {
int i=0;
//关联标志 true-->运行 false-->停止
while(flag) {
System.out.println(name+"-->"+i++);
}
}
//3、对外提供方法改变标志
public void Test7() {
this.flag=false;
}
public static void main(String[] args) {
Test7 tt=new Test7("xiaoha");
new Thread(tt).start();
for(int i=0;i<99;i++) {
if(i==88) {
tt.Test7();
System.out.println("game Over");
}
System.out.println("main-->"+i);
}
}
}
案例:12306购票、龟兔赛跑
自己动手去实现吧
知识点:yield 礼让线程 暂停线程 直接进入就绪状态 不是阻塞状态
public class TestYield {
public static void main(String[] args) {
MyYield my=new MyYield();
new Thread(my,"a").start();
new Thread(my,"b").start();
}
}
class MyYield implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"-->start");;
Thread.yield();
System.out.println(Thread.currentThread().getName()+"-->end");;
}
}
知识点:join:合并线程 插队线程
public class TestJoin {
public static void main(String[] args) {
System.out.println("爸爸和儿子买烟的故事");
new Thread(new Father()).start();
}
}
class Father extends Thread{
public void run() {
System.out.println("想抽烟,发现没了");
System.out.println("让儿子去买烟");
Thread t=new Thread(new Son());
t.start();
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("老爸接过烟,把零钱给了他");
}
}
class Son extends Thread{
public void run() {
System.out.println("接过老爸的钱。。");
System.out.println("路边有个游戏机,玩了一会");
for(int i=0;i<10;i++) {
System.out.println(i+"秒过去了");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("赶紧买烟去。。");
System.out.println("手拿一包烟回家了..");
}
}
知识点:阻塞状态:sleep、join、wait、read、write
public class AllState {
public static void main(String[] args) {
Thread tt=new Thread(()->{
for(int i=0;i<5;i++) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(".....");
});
//观察状态
State state=tt.getState();
System.out.println(state); //NEW
tt.start();
state=tt.getState(); //RUNNING
while(state!=Thread.State.TERMINATED) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
state=tt.getState();
System.out.println(state); //TIMED_WAITING
}
}
}
public class TestPriority {
public static void main(String[] args) {
System.out.println(Thread.currentThread().getPriority());
MyPriority mp=new MyPriority();
Thread t1=new Thread(mp,"红双喜");
Thread t2=new Thread(mp,"回力");
Thread t3=new Thread(mp,"NIKE");
Thread t4=new Thread(mp,"李宁");
t1.setPriority(Thread.NORM_PRIORITY);
t2.setPriority(Thread.MIN_PRIORITY);
t3.setPriority(Thread.MAX_PRIORITY);
t4.setPriority(Thread.MIN_PRIORITY);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
class MyPriority implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"--->"+Thread.currentThread().getPriority());
}
}
知识点:守护线程:是为用户线程服务的;jvm停止不用等待守护线程执行完毕
public class Test8 {
public static void main(String[] args) {
God god=new God();
Ni you=new Ni();
// new Thread(god).start();
Thread t=new Thread(god);
t.setDaemon(true); //将用户线程调整为守护
t.start();
new Thread(you).start();
}
}
class Ni implements Runnable{
@Override
public void run() {
for(int i=0;i<=365*100;i++) {
System.out.println("happy life");
}
System.out.println("hahaah");
}
}
class God implements Runnable{
@Override
public void run() {
for(;true;) {
System.out.println("belss you");
}
}
}
public class Test9 {
public static void main(String[] args) {
System.out.println(Thread.currentThread().isAlive()); //-->true
//设置名称:真实角色+代理角色
MyInfo info=new MyInfo("奥迪");
Thread t=new Thread(info);
t.setName("奔驰");
t.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(t.isAlive()); //-->false
}
}
class MyInfo implements Runnable{
private String name;
public MyInfo(String name) {
this.name=name;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+name);
}
}
public class UnsafeTest1 {
public static void main(String[] args) {
//账户
Account account=new Account(100,"结婚礼金");;
Drawing you=new Drawing(account,80,"可爱的你");
Drawing wife=new Drawing(account,90,"happy");
you.start();
wife.start();
}
}
//账户
class Account{
int money; //金额
String name; //名称
public Account(int money,String name) {
this.money=money;
this.name=name;
}
}
//模拟取款
class Drawing extends Thread{
Account account; //取钱账户
int drawingMoney; //取得钱数
int drawingTotal; //取得总数
int packetTotal; //口袋的总数
public Drawing(Account account, int drawingMoney,String name) {
super(name);
this.account = account;
this.drawingMoney = drawingMoney;
}
@Override
public void run() {
if(account.money-drawingMoney<0){
return ;
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
account.money-=drawingMoney;
packetTotal+=drawingMoney;
System.out.println(this.getName()+"-->"+"账户的余额为:"+account.money);
System.out.println(this.getName()+"-->"+"口袋的钱为:"+packetTotal);
}
}
public class TestSyn {
public static void main(String[] args) {
Cinema c=new Cinema(20,"比高");
new Thread(new Customer(c,3),"xiaoda").start();
new Thread(new Customer(c,2),"xiaoha").start();
}
}
//顾客
class Customer implements Runnable{
Cinema cinema;
int seat;
public Customer(Cinema cinema, int seat) {
super();
this.cinema = cinema;
this.seat = seat;
}
@Override
public void run() {
synchronized (cinema) {
boolean flag=cinema.bookTickets(seat);
if(flag) {
System.out.println("出票成功"+Thread.currentThread().getName()+"--->位置为"+seat);
}else {
System.out.println("出票失败"+Thread.currentThread().getName()+"--->位置不够");
}
}
}
}
//影院
class Cinema{
int available; //可用的位置
String name; //名称
public Cinema(int available, String name) {
super();
this.available = available;
this.name = name;
}
//购票
public boolean bookTickets(int seat) {
System.out.println("可用的位置:"+available);
if(seat>available) {
return false;
};
available-=seat;
return true;
}
}
public class TestSyn{
public static void main(String[] args) {
MakeUp g1=new MakeUp(1,"qiqi");
MakeUp g2=new MakeUp(2,"gaga");
g1.start();
g2.start();
}
}
//口红
class LipStick{
}
//镜子
class Mirror{
}
//化妆
class MakeUp extends Thread{
static LipStick lipstick=new LipStick();
static Mirror mirror=new Mirror();
//选择
int choice;
//名字
String name;
public MakeUp(int choice, String name) {
super();
this.choice = choice;
this.name = name;
}
@Override
public void run() {
//化妆
makeup();
}
//相互持有对方的对象锁-->可能造成死锁
private void makeup() {
if(choice==0) {
synchronized (lipstick) { //获得口红的锁
System.out.println(this.name+"获得口红");
//1秒后想拥有镜子
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// synchronized (mirror) {
// System.out.println(this.name+"获得镜子");
// }
}
synchronized (mirror) {
System.out.println(this.name+"获得镜子");
}
}else {
synchronized (mirror) {
System.out.println(this.name+"获得镜子");
//2秒后想拥有口红
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// synchronized (lipstick) { //获得口红的锁
// System.out.println(this.name+"获得口红");
// }
}
synchronized (lipstick) { //获得口红的锁
System.out.println(this.name+"获得口红");
}
}
}
}
解决方式一:并发协作模型—>管程法
生产者:负责生产数据的模块。(这里的模块可能是:方法。对象。线程、进程)
消费者:负责处理数据的模块。(这里的模块可能是:方法。对象。线程、进程)
缓冲区:消费者不能直接使用生产者的数据,他们之间有个缓冲区
解决方式二:并发协作模型—>信号灯法
public class TestCusPro {
public static void main(String[] args) {
SynContainer container=new SynContainer();
new Producer(container).start();
new Customer(container).start();
}
}
//生产者
class Producer extends Thread{
SynContainer container;
public Producer(SynContainer container) {
this.container=container;
}
public void run() {
//生产
for(int i=0;i<100;i++){
System.out.println("生产"+i+"个商品");
container.push(new Goods(i));
}
}
}
//消费者
class Customer extends Thread{
SynContainer container;
public Customer(SynContainer container) {
this.container=container;
}
public void run() {
//消费
for(int i=0;i<100;i++) { //1000改成100,不然一直在等待
System.out.println("消费"+container.pop().id+"个商品");
}
}
}
//缓冲区
class SynContainer{
Goods[] goods=new Goods[10]; //存储容器
int count=0; //计数器
//存储 生产
public synchronized void push(Goods good) {
//何时能生产 容器存在空间
//不能生产 只有等待
if(count==goods.length) {
try {
this.wait(); //线程阻塞 消费者通知生产解除
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//存在空间 可以生产
goods[count]=good;
count++;
//存在数据 可以通知消费了
this.notifyAll();
}
//获取 消费
public synchronized Goods pop() {
//何时消费 容器中是否存在数据
//没有数据 只能等待
if(count==0) {
try {
this.wait(); //线程阻塞 生产者通知消费解除
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//存在数据可以消费
count--;
Goods good=goods[count];
this.notifyAll(); //存在空间,可以唤醒对方生产
return good;
}
}
//商品
class Goods{
int id;
public Goods(int id) {
super();
this.id = id;
}
}
public class TestXinhaoDe {
public static void main(String[] args) {
TV tv=new TV();
new Player(tv).start();
new Listener(tv).start();
}
}
//生产者 演员
class Player extends Thread{
TV tv;
public Player(TV tv) {
super();
this.tv = tv;
}
public void run() {
for(int i=0;i<20;i++) {
if(i%2==0) {
this.tv.play("music");
}else {
this.tv.play("movie");
}
}
}
}
//消费者 观众
class Listener extends Thread{
TV tv;
public Listener(TV tv) {
super();
this.tv = tv;
}
public void run() {
for(int i=0;i<20;i++) {
tv.Watch();
}
}
}
//同一个资源 电视
class TV{
String voice;
//信号灯
//T 表示演员表演 观众等待
//F 表示观众观看 演员等待
boolean flag=true;
//表演
public synchronized void play(String voice) {
//演员等待
if(!flag) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//表演
System.out.println("表演了"+voice);
this.voice=voice;
//唤醒
this.notifyAll();
//切换标志
this.flag=!this.flag;
}
//观看
public synchronized void Watch() {
//观众等待
if(flag) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//观看
System.out.println("听到了"+voice);
//唤醒
this.notifyAll();
//切换标志
this.flag=!this.flag;
}
}
任务调度:借助Timer和TimerTask类
public class TestTiime {
public static void main(String[] args) {
Timer time=new Timer();
//执行安排
// time.schedule(new MyTask(),1000); //执行任务一次
// time.schedule(new MyTask(),1000,200); //执行多次
Calendar cal=new GregorianCalendar(2021,12,30,12,30,20);
// time.schedule(new MyTask(),new Date(5000L),200); //5秒开始
time.schedule(new MyTask(),cal.getTime(),200);
}
}
//任务类
class MyTask extends TimerTask{
@Override
public void run() {
for(int i=0;i<10;i++) {
System.out.println("休息一会吧");
}
System.out.println("-----end------");
}
}
官网:quartz
HappenBefore:执行代码的顺序可能与编写的代码的不一致,即虚拟机优化代码顺序,则为指令重排。
数据依赖:
/*
* 指令重排:代码的执行顺序与预期的不一致
* 目的:提高性能
*/
public class Test {
//变量1
private static int a=0;
//变量2
private static boolean flag=false;
public static void main(String[] args) throws InterruptedException {
//线程一 更改数据
Thread t1=new Thread(()->{
a=1;
flag=true;
});
//线程二 读取数据
Thread t2=new Thread(()-> {
if(flag) {
a*=1;
}
//指令重排
if(a==0) {
System.out.println("happen before a"+a);
}
});
t1.start();
t2.start();
t1.join();
t2.join();
}
}
代码有些问题,没得到正确的输出。如果哪位大佬知道哪里有错,欢迎留言评论!
volatile保证线程间的变量的可见性。
目的:为了提高效率
volatile是不错的机制,但是volatile不能保证原子性。
/*
* volatile:用于保证数据的同步,也就是可见性
*/
public class Testvolatile {
// private static int num=0;
private volatile static int num=0;
public static void main(String[] args) throws InterruptedException {
new Thread(()->{
while(num==0) { //此处不要编写代码
}
}).start();
Thread.sleep(1000);
num=1;
}
}
dcl单例模式:懒汉式套路的基础上,保证在多线程环境下,对外存在一个对象
public class Test1 {
//2、提供私有的静态属性
private volatile static Test1 instance; //避免指令重排
//没有volatile其他线程可能访问一个没有初始化的对象
//1、构造器私有化
private Test1() {
}
//3、提供公共的静态方法
public static Test1 getInstance() {
//再次检测
if(null!=instance) { //避免不必要的同步,已经存在对象
return instance;
}
synchronized (Test1.class) {
if(null==instance) {
instance=new Test1();
//(new做的三件事):1、开辟空间 2、初始化对象信息 3、返回对象的地址给引用
}
}
return instance;
}
public static void main(String[] args) {
Thread t=new Thread(()->{
System.out.println(Test1.getInstance());
});
t.start();
System.out.println(Test1.getInstance());
}
}
ThreadLocal最常用的地方就是为每个线程绑定一个数据库链接,HTTP请求,用户身份信息等。这样一个线程的所有调用到的方法都可以非常方便的访问这些资源。
/*
* ThreadLoacal:每个线程自身的存储本地。局部区域
* get/set/initialValue
*/
public class Test3 {
// private static ThreadLocal threadLocal=new ThreadLocal<>();
//更改初始值
// private static ThreadLocal threadLocal=new ThreadLocal<>() {
// protected Integer initialValue() {
// return 200;
// };
// };
/*
* 方式二:lambda
*/
private static ThreadLocal<Integer> threadLocal=ThreadLocal.withInitial(()->200);
public static void main(String[] args) {
//获取值
// System.out.println(Thread.currentThread().getName()+"-->"+threadLocal.get()); //-->main-->null
System.out.println(Thread.currentThread().getName()+"-->"+threadLocal.get()); //-->main-->200
//设置值
threadLocal.set(99);
System.out.println(Thread.currentThread().getName()+"-->"+threadLocal.get()); //-->main-->99
}
}
ThreadLocal:分析上下文 环境 起点
1、构造器:哪里调用就属于哪里
2、run方法:本线程自身的
InheritableThreadLocal: 继承上下文 环境的数据 起点 拷贝一份给子线程
public class Test4 {
public void test() {
//第一次获得锁
synchronized (this) {
while(true) {
//第二次获得同样的锁
synchronized (this) {
System.out.println("ReentrantLock");
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
new Test4().test();
}
}
public class Test4{
Lock lock=new Lock();
public void a() throws InterruptedException {
lock.lock();
doSomething();
lock.unlock();
}
//不可重入
public void doSomething() {
try {
lock.lock();
} catch (InterruptedException e) {
e.printStackTrace();
}
lock.unlock();
}
public static void main(String[] args) throws InterruptedException {
Test4 test=new Test4();
test.a();
test.doSomething();
}
}
//不可重入锁
class Lock{
//是否占用
private boolean isLocked=false;
//使用锁
public synchronized void lock() throws InterruptedException {
while(isLocked) {
wait();
}
isLocked=true;
}
//释放锁
public synchronized void unlock() {
}
}
锁分为两类:
(1)悲观锁:synchronized是独占锁即悲观锁,会导致其他所有需要锁的线程挂起,等待持有锁的线程释放锁。
(2)乐观锁:每次不加锁而是假设没有冲突而去完成某项操作,如果因为冲突失败就重试。直到成功为止。
/*
* CAS:比较并交换
*/
public class CAS {
//库存
private static AtomicInteger stock=new AtomicInteger(5);
public static void main(String[] args) {
for(int i=0;i<5;i++) {
new Thread(()->{
//模拟网络延时
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Integer left=stock.decrementAndGet();
if(left<1) {
System.out.println("抢完了....");
return ;
}
System.out.println(Thread.currentThread().getName()+"抢了一件商品");
System.out.println("-->还剩"+left);
}).start();
}
}
}
上篇博文:学习Java_IO_File看这篇就够了